1 /*
2 SPDX-License-Identifier: GPL-2.0-or-later
3
4 SPDX-FileCopyrightText: 2002 Oliver Kellogg <okellogg@users.sourceforge.net>
5 SPDX-FileCopyrightText: 2003-2021 Umbrello UML Modeller Authors <umbrello-devel@kde.org>
6 */
7
8 #include "adawriter.h"
9
10 #include "debug_utils.h"
11 #include "umldoc.h"
12 #include "uml.h"
13 #include "classifier.h"
14 #include "enum.h"
15 #include "classifierlistitem.h"
16 #include "umlclassifierlistitemlist.h"
17 #include "umltemplatelist.h"
18 #include "folder.h"
19 #include "association.h"
20 #include "attribute.h"
21 #include "operation.h"
22 #include "template.h"
23
24 #include <KLocalizedString>
25 #include <KMessageBox>
26
27 #include <QFile>
28 #include <QRegExp>
29 #include <QTextStream>
30
31 const QString AdaWriter::defaultPackageSuffix = QLatin1String("_Holder");
32
33 /**
34 * Basic Constructor
35 */
AdaWriter()36 AdaWriter::AdaWriter()
37 : SimpleCodeGenerator()
38 {
39 m_indentLevel = 1; // due to different handling, see finalizeRun()
40 }
41
42 /**
43 * Empty Destructor
44 */
~AdaWriter()45 AdaWriter::~AdaWriter()
46 {
47 }
48
49 /**
50 * Returns "Ada".
51 * @return the programming language identifier
52 */
language() const53 Uml::ProgrammingLanguage::Enum AdaWriter::language() const
54 {
55 return Uml::ProgrammingLanguage::Ada;
56 }
57
58 /**
59 * Return true if `c' is a tagged type or Ada2005 interface.
60 */
isOOClass(UMLClassifier * c)61 bool AdaWriter::isOOClass(UMLClassifier *c)
62 {
63 UMLObject::ObjectType ot = c->baseType();
64 if (ot == UMLObject::ot_Interface)
65 return true;
66 if (ot == UMLObject::ot_Enum)
67 return false;
68 if (ot != UMLObject::ot_Class) {
69 uDebug() << "unknown object type " << UMLObject::toString(ot);
70 return false;
71 }
72 QString stype = c->stereotype();
73 if (stype == QLatin1String("CORBAConstant") || stype == QLatin1String("CORBATypedef") ||
74 stype == QLatin1String("CORBAStruct") || stype == QLatin1String("CORBAUnion"))
75 return false;
76 // CORBAValue, CORBAInterface, and all empty/unknown stereotypes are
77 // assumed to be object oriented classes.
78 return true;
79 }
80
81 /**
82 * Returns the class name.
83 */
className(UMLClassifier * c,bool inOwnScope)84 QString AdaWriter::className(UMLClassifier *c, bool inOwnScope)
85 {
86 // If the class has an enclosing package then it is assumed that
87 // the class name is the type name; if the class does not have an
88 // enclosing package then the class name acts as the Ada package
89 // name.
90 QString retval;
91 QString className = cleanName(c->name());
92 UMLPackage *umlPkg = c->umlPackage();
93 if (umlPkg == UMLApp::app()->document()->rootFolder(Uml::ModelType::Logical)) {
94 if (! inOwnScope)
95 retval = className + QLatin1Char('.');
96 retval.append(QLatin1String("Object"));
97 } else {
98 if (! inOwnScope)
99 retval = umlPkg->fullyQualifiedName(QLatin1String(".")) + QLatin1Char('.');
100 retval.append(className);
101 }
102 return retval;
103 }
104
105 /**
106 * Returns the package name.
107 */
packageName(UMLPackage * p)108 QString AdaWriter::packageName(UMLPackage *p)
109 {
110 // If the class has an enclosing package then it is assumed that
111 // the class name is the type name; if the class does not have an
112 // enclosing package then the class name acts as the Ada package
113 // name.
114 UMLPackage *umlPkg = p->umlPackage();
115 QString className = cleanName(p->name());
116 QString retval;
117
118 if (umlPkg == UMLApp::app()->document()->rootFolder(Uml::ModelType::Logical))
119 umlPkg = 0;
120
121 UMLClassifier *c = p->asUMLClassifier();
122 if (umlPkg == 0) {
123 retval = className;
124 if (c == 0 || !isOOClass(c))
125 retval.append(defaultPackageSuffix);
126 } else {
127 retval = umlPkg->fullyQualifiedName(QLatin1String("."));
128 }
129 return retval;
130 }
131
132 /**
133 * Compute the type and role name from the given association.
134 *
135 * @param c The UMLClassifier for which code is being generated.
136 * @param a The UMLAssociation to analyze.
137 * @param typeName Return value: type name.
138 * @param roleName Return value: role name.
139 */
computeAssocTypeAndRole(UMLClassifier * c,UMLAssociation * a,QString & typeName,QString & roleName)140 void AdaWriter::computeAssocTypeAndRole(UMLClassifier *c,
141 UMLAssociation *a,
142 QString& typeName, QString& roleName)
143 {
144 UMLClassifier* assocEnd = a->getObject(Uml::RoleType::B)->asUMLClassifier();
145 if (assocEnd == 0)
146 return;
147 const Uml::AssociationType::Enum assocType = a->getAssocType();
148 if (assocType != Uml::AssociationType::Aggregation && assocType != Uml::AssociationType::Composition)
149 return;
150 const QString multi = a->getMultiplicity(Uml::RoleType::B);
151 bool hasNonUnityMultiplicity = (!multi.isEmpty() && multi != QLatin1String("1"));
152 hasNonUnityMultiplicity &= !multi.contains(QRegExp(QLatin1String("^1 *\\.\\. *1$")));
153 roleName = cleanName(a->getRoleName(Uml::RoleType::B));
154 if (roleName.isEmpty())
155 roleName = cleanName(a->name());
156 if (roleName.isEmpty()) {
157 QString artificialName = cleanName(assocEnd->name());
158 if (hasNonUnityMultiplicity) {
159 roleName = artificialName;
160 roleName.append(QLatin1String("_Vector"));
161 } else {
162 roleName = QLatin1String("M_");
163 roleName.append(artificialName);
164 }
165 }
166 typeName = className(assocEnd, (assocEnd == c));
167 if (hasNonUnityMultiplicity)
168 typeName.append(QLatin1String("_Array_Ptr"));
169 else if (assocType == Uml::AssociationType::Aggregation)
170 typeName.append(QLatin1String("_Ptr"));
171 }
172
declareClass(UMLClassifier * c,QTextStream & ada)173 void AdaWriter::declareClass(UMLClassifier *c, QTextStream &ada)
174 {
175 UMLClassifierList superclasses = c->getSuperClasses();
176 UMLClassifier *firstSuperClass = 0;
177 if (!superclasses.isEmpty()) {
178 foreach (UMLClassifier* super, superclasses) {
179 if (!super->isInterface()) {
180 firstSuperClass = super;
181 break;
182 }
183 }
184 if (firstSuperClass == 0)
185 firstSuperClass = superclasses.first();
186 }
187 const QString name = className(c);
188 ada << indent() << "type " << name << " is ";
189 if (c->isAbstract())
190 ada << "abstract ";
191 if (superclasses.isEmpty()) {
192 ada << "tagged ";
193 } else {
194 ada << "new " << className(firstSuperClass, false);
195 foreach (UMLClassifier* super, superclasses) {
196 if (super->isInterface() && super != firstSuperClass)
197 ada << " and " << className(super, false);
198 }
199 ada << " with ";
200 }
201 }
202
203 /**
204 * Call this method to generate Ada code for a UMLClassifier.
205 * @param c the class to generate code for
206 */
writeClass(UMLClassifier * c)207 void AdaWriter::writeClass(UMLClassifier *c)
208 {
209 if (!c) {
210 uDebug() << "Cannot write class of NULL concept!";
211 return;
212 }
213 if (m_classesGenerated.contains(c))
214 return;
215
216 const bool isClass = !c->isInterface();
217 QString classname = cleanName(c->name());
218 QString pkg = packageName(c);
219 QString fileName = pkg.toLower();
220 fileName.replace(QLatin1Char('.'), QLatin1Char('-'));
221
222 //find an appropriate name for our file
223 fileName = overwritableName(c, fileName, QLatin1String(".ads"));
224 if (fileName.isEmpty()) {
225 emit codeGenerated(c, false);
226 return;
227 }
228
229 QFile *file = 0;
230 bool isNewFile = false;
231 PackageFileMap::iterator it = m_pkgsGenerated.find(pkg);
232 if (it != m_pkgsGenerated.end()) {
233 file = it.value();
234 } else {
235 file = new QFile();
236 if (!openFile(*file, fileName)) {
237 emit codeGenerated(c, false);
238 delete file;
239 return;
240 }
241 m_pkgsGenerated[pkg] = file;
242 isNewFile = true;
243 }
244
245 // Start generating the code.
246
247 QTextStream ada(file);
248 if (isNewFile) {
249 //try to find a heading file(license, comments, etc)
250 QString str;
251 str = getHeadingFile(QLatin1String(".ads"));
252 if (!str.isEmpty()) {
253 str.replace(QRegExp(QLatin1String("%filename%")), fileName);
254 str.replace(QRegExp(QLatin1String("%filepath%")), file->fileName());
255 ada << str << m_endl;
256 }
257
258 // Import referenced classes.
259 UMLPackageList imports;
260 findObjectsRelated(c, imports);
261 if (imports.count()) {
262 foreach (UMLPackage* con, imports) {
263 if (con->isUMLDatatype())
264 continue;
265 QString pkgDep = packageName(con);
266 if (pkgDep != pkg)
267 ada << "with " << pkgDep << "; " << m_endl;
268 }
269 ada << m_endl;
270 }
271
272 // Generate generic formals.
273 UMLTemplateList template_params = c->getTemplateList();
274 if (template_params.count()) {
275 ada << indent() << "generic" << m_endl;
276 m_indentLevel++;
277 foreach (UMLTemplate* t, template_params) {
278 QString formalName = t->name();
279 QString typeName = t->getTypeName();
280 if (typeName == QLatin1String("class")) {
281 ada << indent() << "type " << formalName << " is tagged private;"
282 << m_endl;
283 } else {
284 // Check whether it's a data type.
285 UMLClassifier *typeObj = t->getType();
286 if (typeObj == 0) {
287 uError() << "template_param " << typeName << ": typeObj is NULL";
288 ada << indent() << "type " << formalName << " is new " << typeName
289 << " with private; -- CHECK: codegen error"
290 << m_endl;
291 } else if (typeObj->isUMLDatatype()) {
292 ada << indent() << formalName << " : " << typeName << ";"
293 << m_endl;
294 } else {
295 ada << indent() << "type " << typeName << " is new "
296 << formalName << " with private;" << m_endl;
297 }
298 }
299 }
300 m_indentLevel--;
301 }
302
303 // Here comes the package proper.
304 ada << "package " << pkg << " is" << m_endl << m_endl;
305 }
306
307 if (c->baseType() == UMLObject::ot_Enum) {
308 UMLEnum *ue = c->asUMLEnum();
309 UMLClassifierListItemList litList = ue->getFilteredList(UMLObject::ot_EnumLiteral);
310 uint i = 0;
311 ada << indent() << "type " << classname << " is (" << m_endl;
312 m_indentLevel++;
313 foreach (UMLClassifierListItem* lit, litList) {
314 QString enumLiteral = cleanName(lit->name());
315 ada << indent() << enumLiteral;
316 if (++i < (uint)litList.count())
317 ada << "," << m_endl;
318 }
319 m_indentLevel--;
320 ada << ");" << m_endl << m_endl;
321 ada << "end " << pkg << ";" << m_endl << m_endl;
322 return;
323 }
324 if (! isOOClass(c)) {
325 QString stype = c->stereotype();
326 if (stype == QLatin1String("CORBAConstant")) {
327 ada << indent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl;
328 } else if (stype == QLatin1String("CORBAStruct")) {
329 if (isClass) {
330 UMLAttributeList atl = c->getAttributeList();
331 ada << indent() << "type " << classname << " is record" << m_endl;
332 m_indentLevel++;
333 foreach (UMLAttribute* at, atl) {
334 QString name = cleanName(at->name());
335 QString typeName = at->getTypeName();
336 ada << indent() << name << " : " << typeName;
337 QString initialVal = at->getInitialValue();
338 if (! initialVal.isEmpty() && ! initialVal.toLatin1().isEmpty())
339 ada << " := " << initialVal;
340 ada << ";" << m_endl;
341 }
342 m_indentLevel--;
343 ada << indent() << "end record;" << m_endl << m_endl;
344 }
345 } else if (stype == QLatin1String("CORBAUnion")) {
346 ada << indent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl;
347 } else if (stype == QLatin1String("CORBATypedef")) {
348 ada << indent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl;
349 } else {
350 ada << indent() << "-- " << stype << ": Unknown stereotype" << m_endl << m_endl;
351 }
352 ada << "end " << pkg << ";" << m_endl << m_endl;
353 return;
354 }
355
356 UMLClassifierList superclasses = c->getSuperClasses();
357 if (!superclasses.isEmpty()) {
358 // Ensure that superclasses in same package are declared before this class.
359 foreach (UMLClassifier* super, superclasses) {
360 if (packageName(super) == pkg && !m_classesGenerated.contains(super)) {
361 writeClass(super);
362 }
363 }
364 }
365 m_classesGenerated.append(c);
366
367 // Write class Documentation if non-empty or if force option set.
368 if (forceDoc() || !c->doc().isEmpty()) {
369 ada << "--" << m_endl;
370 ada << "-- class " << classname << m_endl;
371 ada << formatDoc(c->doc(), QLatin1String("-- "));
372 ada << m_endl;
373 }
374
375 const QString name = className(c);
376 if (isClass) {
377 declareClass(c, ada);
378 ada << "private;" << m_endl << m_endl;
379 } else {
380 ada << indent() << "type " << name << " is interface";
381 foreach (UMLClassifier* super, superclasses) {
382 if (super->isInterface())
383 ada << " and " << className(super, false);
384 }
385 ada << ";" << m_endl << m_endl;
386 }
387 ada << indent() << "type " << name << "_Ptr is access all " << name << "'Class;" << m_endl << m_endl;
388 ada << indent() << "type " << name << "_Array is array (Positive range <>) of " << name << "_Ptr;" << m_endl << m_endl;
389 ada << indent() << "type " << name << "_Array_Ptr is access " << name << "_Array;" << m_endl << m_endl;
390
391 // Generate accessors for public attributes.
392 UMLAttributeList atl;
393 if (isClass) {
394 UMLAttributeList atpub;
395
396 atl = c->getAttributeList();
397
398 foreach (UMLAttribute* at, atl) {
399 if (at->visibility() == Uml::Visibility::Public)
400 atpub.append(at);
401 }
402 if (forceSections() || atpub.count())
403 ada << indent() << "-- Accessors for public attributes:" << m_endl << m_endl;
404
405 foreach (UMLAttribute* at, atpub) {
406 QString member = cleanName(at->name());
407 ada << indent() << "procedure Set_" << member << " (";
408 if (! at->isStatic())
409 ada << "Self : access " << name << "; ";
410 ada << "To : " << at->getTypeName() << ");" << m_endl;
411 ada << indent() << "function Get_" << member;
412 if (! at->isStatic())
413 ada << " (Self : access " << name << ")";
414 ada << " return " << at->getTypeName() << ";" << m_endl << m_endl;
415 }
416 }
417
418 // Generate public operations.
419 UMLOperationList opl(c->getOpList());
420 UMLOperationList oppub;
421 foreach (UMLOperation* op, opl) {
422 if (op->visibility() == Uml::Visibility::Public)
423 oppub.append(op);
424 }
425 if (forceSections() || oppub.count())
426 ada << indent() << "-- Public methods:" << m_endl << m_endl;
427
428 foreach (UMLOperation* op, oppub) {
429 writeOperation(op, ada);
430 }
431
432 emit codeGenerated(c, true);
433 }
434
435 /**
436 * Write one operation.
437 * @param op the class for which we are generating code
438 * @param ada the stream associated with the output file
439 * @param is_comment flag for a comment
440 */
writeOperation(UMLOperation * op,QTextStream & ada,bool is_comment)441 void AdaWriter::writeOperation(UMLOperation *op, QTextStream &ada, bool is_comment)
442 {
443 UMLAttributeList atl = op->getParmList();
444 QString rettype = op->getTypeName();
445 bool use_procedure = (rettype.isEmpty() || rettype == QLatin1String("void"));
446
447 ada << indent();
448 if (is_comment)
449 ada << "-- ";
450 if (use_procedure)
451 ada << "procedure ";
452 else
453 ada << "function ";
454 ada << cleanName(op->name()) << " ";
455 if (! (op->isStatic() && atl.count() == 0))
456 ada << "(";
457 UMLClassifier *parentClassifier = op->umlParent()->asUMLClassifier();
458 if (! op->isStatic()) {
459 ada << "Self : access " << className(parentClassifier);
460 if (atl.count())
461 ada << ";" << m_endl;
462 }
463 if (atl.count()) {
464 uint i = 0;
465 m_indentLevel++;
466 foreach (UMLAttribute* at, atl) {
467 ada << indent();
468 if (is_comment)
469 ada << "-- ";
470 ada << cleanName(at->name()) << " : ";
471 Uml::ParameterDirection::Enum pk = at->getParmKind();
472 if (pk == Uml::ParameterDirection::Out)
473 ada << "out ";
474 else if (pk == Uml::ParameterDirection::InOut)
475 ada << "in out ";
476 else
477 ada << "in ";
478 ada << at->getTypeName();
479 if (! at->getInitialValue().isEmpty())
480 ada << " := " << at->getInitialValue();
481 if (++i < (uint)atl.count()) //FIXME gcc warning
482 ada << ";" << m_endl;
483 }
484 m_indentLevel--;
485 }
486 if (! (op->isStatic() && atl.count() == 0))
487 ada << ")";
488 if (! use_procedure)
489 ada << " return " << rettype;
490 if (op->isAbstract())
491 ada << " is abstract";
492 ada << ";" << m_endl << m_endl;
493 }
494
495 /**
496 * Returns the default datatypes.
497 */
defaultDatatypes() const498 QStringList AdaWriter::defaultDatatypes() const
499 {
500 QStringList l;
501 l.append(QLatin1String("Boolean"));
502 l.append(QLatin1String("Character"));
503 l.append(QLatin1String("Positive"));
504 l.append(QLatin1String("Natural"));
505 l.append(QLatin1String("Integer"));
506 l.append(QLatin1String("Short_Integer"));
507 l.append(QLatin1String("Long_Integer"));
508 l.append(QLatin1String("Float"));
509 l.append(QLatin1String("Long_Float"));
510 l.append(QLatin1String("Duration"));
511 l.append(QLatin1String("String"));
512 return l;
513 }
514
515 /**
516 * Check whether the given string is a reserved word for the
517 * language of this code generator
518 *
519 * @param rPossiblyReservedKeyword The string to check.
520 */
isReservedKeyword(const QString & rPossiblyReservedKeyword)521 bool AdaWriter::isReservedKeyword(const QString & rPossiblyReservedKeyword)
522 {
523 const QStringList keywords = reservedKeywords();
524
525 QStringList::ConstIterator it;
526 for (it = keywords.begin(); it != keywords.end(); ++it) {
527 if ((*it).toLower() == rPossiblyReservedKeyword.toLower()) {
528 return true;
529 }
530 }
531 return false;
532 }
533
534 /**
535 * Get list of reserved keywords.
536 * @return the list of reserved keywords
537 */
reservedKeywords() const538 QStringList AdaWriter::reservedKeywords() const
539 {
540 static QStringList keywords;
541
542 if (keywords.isEmpty()) {
543 keywords.append(QLatin1String("abort"));
544 keywords.append(QLatin1String("abs"));
545 keywords.append(QLatin1String("abstract"));
546 keywords.append(QLatin1String("accept"));
547 keywords.append(QLatin1String("access"));
548 keywords.append(QLatin1String("aliased"));
549 keywords.append(QLatin1String("all"));
550 keywords.append(QLatin1String("and"));
551 keywords.append(QLatin1String("Argument_Error"));
552 keywords.append(QLatin1String("array"));
553 keywords.append(QLatin1String("Assert_Failure"));
554 keywords.append(QLatin1String("at"));
555 keywords.append(QLatin1String("begin"));
556 keywords.append(QLatin1String("body"));
557 keywords.append(QLatin1String("Boolean"));
558 keywords.append(QLatin1String("case"));
559 keywords.append(QLatin1String("Character"));
560 keywords.append(QLatin1String("constant"));
561 keywords.append(QLatin1String("Constraint_Error"));
562 keywords.append(QLatin1String("Conversion_Error"));
563 keywords.append(QLatin1String("Data_Error"));
564 keywords.append(QLatin1String("declare"));
565 keywords.append(QLatin1String("delay"));
566 keywords.append(QLatin1String("delta"));
567 keywords.append(QLatin1String("Dereference_Error"));
568 keywords.append(QLatin1String("Device_Error"));
569 keywords.append(QLatin1String("digits"));
570 keywords.append(QLatin1String("do"));
571 keywords.append(QLatin1String("Duration"));
572 keywords.append(QLatin1String("else"));
573 keywords.append(QLatin1String("elsif"));
574 keywords.append(QLatin1String("end"));
575 keywords.append(QLatin1String("End_Error"));
576 keywords.append(QLatin1String("entry"));
577 keywords.append(QLatin1String("exception"));
578 keywords.append(QLatin1String("exit"));
579 keywords.append(QLatin1String("false"));
580 keywords.append(QLatin1String("Float"));
581 keywords.append(QLatin1String("for"));
582 keywords.append(QLatin1String("function"));
583 keywords.append(QLatin1String("generic"));
584 keywords.append(QLatin1String("goto"));
585 keywords.append(QLatin1String("if"));
586 keywords.append(QLatin1String("in"));
587 keywords.append(QLatin1String("Index_Error"));
588 keywords.append(QLatin1String("Integer"));
589 keywords.append(QLatin1String("interface"));
590 keywords.append(QLatin1String("is"));
591 keywords.append(QLatin1String("Layout_Error"));
592 keywords.append(QLatin1String("Length_Error"));
593 keywords.append(QLatin1String("limited"));
594 keywords.append(QLatin1String("Long_Float"));
595 keywords.append(QLatin1String("Long_Integer"));
596 keywords.append(QLatin1String("Long_Long_Float"));
597 keywords.append(QLatin1String("Long_Long_Integer"));
598 keywords.append(QLatin1String("loop"));
599 keywords.append(QLatin1String("mod"));
600 keywords.append(QLatin1String("Mode_Error"));
601 keywords.append(QLatin1String("Name_Error"));
602 keywords.append(QLatin1String("Natural"));
603 keywords.append(QLatin1String("new"));
604 keywords.append(QLatin1String("not"));
605 keywords.append(QLatin1String("null"));
606 keywords.append(QLatin1String("of"));
607 keywords.append(QLatin1String("or"));
608 keywords.append(QLatin1String("others"));
609 keywords.append(QLatin1String("out"));
610 keywords.append(QLatin1String("package"));
611 keywords.append(QLatin1String("Pattern_Error"));
612 keywords.append(QLatin1String("Picture_Error"));
613 keywords.append(QLatin1String("Pointer_Error"));
614 keywords.append(QLatin1String("Positive"));
615 keywords.append(QLatin1String("pragma"));
616 keywords.append(QLatin1String("private"));
617 keywords.append(QLatin1String("procedure"));
618 keywords.append(QLatin1String("Program_Error"));
619 keywords.append(QLatin1String("protected"));
620 keywords.append(QLatin1String("raise"));
621 keywords.append(QLatin1String("range"));
622 keywords.append(QLatin1String("record"));
623 keywords.append(QLatin1String("rem"));
624 keywords.append(QLatin1String("renames"));
625 keywords.append(QLatin1String("requeue"));
626 keywords.append(QLatin1String("return"));
627 keywords.append(QLatin1String("reverse"));
628 keywords.append(QLatin1String("select"));
629 keywords.append(QLatin1String("separate"));
630 keywords.append(QLatin1String("Short_Float"));
631 keywords.append(QLatin1String("Short_Integer"));
632 keywords.append(QLatin1String("Short_Short_Float"));
633 keywords.append(QLatin1String("Short_Short_Integer"));
634 keywords.append(QLatin1String("Status_Error"));
635 keywords.append(QLatin1String("Storage_Error"));
636 keywords.append(QLatin1String("String"));
637 keywords.append(QLatin1String("subtype"));
638 keywords.append(QLatin1String("Tag_Error"));
639 keywords.append(QLatin1String("tagged"));
640 keywords.append(QLatin1String("task"));
641 keywords.append(QLatin1String("Tasking_Error"));
642 keywords.append(QLatin1String("terminate"));
643 keywords.append(QLatin1String("Terminator_Error"));
644 keywords.append(QLatin1String("then"));
645 keywords.append(QLatin1String("Time_Error"));
646 keywords.append(QLatin1String("Translation_Error"));
647 keywords.append(QLatin1String("true"));
648 keywords.append(QLatin1String("type"));
649 keywords.append(QLatin1String("until"));
650 keywords.append(QLatin1String("Update_Error"));
651 keywords.append(QLatin1String("use"));
652 keywords.append(QLatin1String("Use_Error"));
653 keywords.append(QLatin1String("when"));
654 keywords.append(QLatin1String("while"));
655 keywords.append(QLatin1String("Wide_Character"));
656 keywords.append(QLatin1String("Wide_String"));
657 keywords.append(QLatin1String("with"));
658 keywords.append(QLatin1String("xor"));
659 }
660
661 return keywords;
662 }
663
finalizeRun()664 void AdaWriter::finalizeRun()
665 {
666 PackageFileMap::iterator end(m_pkgsGenerated.end());
667 for (PackageFileMap::iterator i = m_pkgsGenerated.begin(); i != end; ++i) {
668 QString pkg = i.key();
669 QFile *file = i.value();
670 QTextStream ada(file);
671 ada << m_endl << "private" << m_endl << m_endl;
672 foreach (UMLClassifier* c, m_classesGenerated) {
673 if (packageName(c) != pkg)
674 continue;
675 bool isClass = !c->isInterface();
676 if (isClass) {
677 declareClass(c, ada);
678 ada << "record" << m_endl;
679 m_indentLevel++;
680
681 UMLAssociationList aggregations = c->getAggregations();
682 UMLAssociationList compositions = c->getCompositions();
683
684 if (forceSections() || !aggregations.isEmpty()) {
685 ada << indent() << "-- Aggregations:" << m_endl;
686 foreach (UMLAssociation *a, aggregations) {
687 if (c != a->getObject(Uml::RoleType::A))
688 continue;
689 QString typeName, roleName;
690 computeAssocTypeAndRole(c, a, typeName, roleName);
691 ada << indent() << roleName << " : " << typeName << ";" << m_endl;
692 }
693 ada << m_endl;
694 }
695 if (forceSections() || !compositions.isEmpty()) {
696 ada << indent() << "-- Compositions:" << m_endl;
697 foreach (UMLAssociation *a, compositions) {
698 if (c != a->getObject(Uml::RoleType::A))
699 continue;
700 QString typeName, roleName;
701 computeAssocTypeAndRole(c, a, typeName, roleName);
702 ada << indent() << roleName << " : " << typeName << ";" << m_endl;
703 }
704 ada << m_endl;
705 }
706
707 UMLAttributeList atl = c->getAttributeList();
708 if (forceSections() || atl.count()) {
709 ada << indent() << "-- Attributes:" << m_endl;
710 foreach (UMLAttribute* at, atl) {
711 if (!at || at->isStatic())
712 continue;
713 ada << indent() << cleanName(at->name()) << " : "
714 << at->getTypeName();
715 if (!at->getInitialValue().isEmpty() && !at->getInitialValue().toLatin1().isEmpty())
716 ada << " := " << at->getInitialValue();
717 ada << ";" << m_endl;
718 }
719 }
720 const bool haveAttrs = (atl.count() != 0);
721 if (aggregations.isEmpty() && compositions.isEmpty() && !haveAttrs)
722 ada << indent() << "null;" << m_endl;
723 m_indentLevel--;
724 ada << indent() << "end record;" << m_endl << m_endl;
725 if (haveAttrs) {
726 bool seen_static_attr = false;
727 foreach (UMLAttribute* at, atl) {
728 if (! at->isStatic())
729 continue;
730 if (! seen_static_attr) {
731 ada << indent() << "-- Static attributes:" << m_endl;
732 seen_static_attr = true;
733 }
734 ada << indent();
735 if (at->visibility() == Uml::Visibility::Private)
736 ada << "-- Private: ";
737 ada << cleanName(at->name()) << " : " << at->getTypeName();
738 if (at && ! at->getInitialValue().isEmpty() && ! at->getInitialValue().toLatin1().isEmpty())
739 ada << " := " << at->getInitialValue();
740 ada << ";" << m_endl;
741 }
742 if (seen_static_attr)
743 ada << m_endl;
744 }
745 }
746 UMLOperationList opl(c->getOpList());
747 // Generate protected operations.
748 UMLOperationList opprot;
749 foreach (UMLOperation* op, opl) {
750 if (op->visibility() == Uml::Visibility::Protected)
751 opprot.append(op);
752 }
753 if (forceSections() || opprot.count())
754 ada << indent() << "-- Protected methods:" << m_endl << m_endl;
755 foreach (UMLOperation* op, opprot) {
756 writeOperation(op, ada);
757 }
758
759 // Generate private operations.
760 // These are currently only generated as comments in the private part
761 // of the spec.
762 // Once umbrello supports the merging of automatically generated and
763 // hand written code sections, private operations should be generated
764 // into the package body.
765 UMLOperationList oppriv;
766 foreach (UMLOperation* op, opl) {
767 const Uml::Visibility::Enum vis = op->visibility();
768 if (vis == Uml::Visibility::Private ||
769 vis == Uml::Visibility::Implementation)
770 oppriv.append(op);
771 }
772 if (forceSections() || oppriv.count())
773 ada << indent() << "-- Private methods:" << m_endl << m_endl;
774 foreach (UMLOperation* op, oppriv) {
775 writeOperation(op, ada, true);
776 }
777 }
778 ada << m_endl << "end " << i.key() << ";" << m_endl;
779 file->close();
780 emit showGeneratedFile(file->fileName());
781 delete file;
782 }
783 }
784
785
786