void UmlClass::addContructor(bool expl) { TRACE_FUNCTION; QLOG_INFO() << "1.1.1"; UmlOperation * op = UmlOperation::create(this, name()); QLOG_INFO() << "1.1.2"; if (op == 0) UmlCom::trace("can't add contructor"); else { QLOG_INFO() << "1.1.3"; QByteArray s; int index; // remove the useless "${type} " mainly to remove the space s = op->cppDecl(); QLOG_INFO() << s; QLOG_INFO() << "1.1.4"; if (s.isEmpty()) s = CppSettings::operationDecl(); QLOG_INFO() << s; QLOG_INFO() << "1.1.5"; if ((index = s.indexOf("${type} ")) != -1) s.remove(index, 8); QLOG_INFO() << s; QLOG_INFO() << "1.1.6"; if (expl && ((index = s.indexOf("${name}")) != -1)) s.insert(index, "explicit "); QLOG_INFO() << s; QLOG_INFO() << "1.1.7"; op->set_CppDecl(s); QLOG_INFO() << s; QLOG_INFO() << "1.1.8"; s = op->cppDef(); QLOG_INFO() << s; QLOG_INFO() << "1.1.81"; if (s.isEmpty()) s = CppSettings::operationDef(); QLOG_INFO() << "1.1.9"; if ((index = s.indexOf("${type} ")) != -1) s.remove(index, 8); QLOG_INFO() << "1.1.10"; op->set_CppDef(s); } }
void UmlJunctionPseudoState::generate(UmlClass * machine, UmlClass * anystate, UmlState * state) { // create an operation because a priori shared if (_oper.isEmpty()) _oper.sprintf("_junction%d", ++_rank); UmlClass * cl = state->assocClass(); UmlOperation * junction; if (((junction = (UmlOperation *) cl->getChild(anOperation, _oper)) == 0) && ((junction = UmlBaseOperation::create(cl, _oper)) == 0)) { UmlCom::trace("Error : cannot create operation '" + _oper + "' in class '" + cl->name() + "'<br>"); throw 0; } junction->defaultDef(); junction->setComment("implement a junction, through an operation because shared, internal"); junction->setType("void", "${type}"); junction->addParam(0, InputOutputDirection, "stm", machine); junction->setParams("${t0} & ${p0}"); Q3CString body; const Q3PtrVector<UmlItem> ch = children(); Q3PtrList<UmlTransition> trs; unsigned index; for (index = 0; index != ch.count(); index += 1) if (ch[index]->kind() == aTransition) // theo mandatory trs.append((UmlTransition *) ch[index]); UmlTransition::generate(trs, machine, anystate, state, body, " ", FALSE); junction->set_CppBody(body); }
void UmlClass::addAssign(bool cte) { TRACE_FUNCTION; UmlOperation * op = UmlOperation::create(this, "operator="); if (op == 0) UmlCom::trace("can't add assignment contructor"); else { // add 'source' parameter UmlParameter param; param.name = "source"; param.dir = (cte) ? InputDirection : InputOutputDirection; param.type.type = this; op->addParameter(0, param); // set return type, add the parameter profile UmlTypeSpec t; t.type = this; op->set_ReturnType(t); QByteArray p = (cte) ? "const ${t0} & ${p0}" : "${t0} & ${p0}"; QByteArray s; int index; s = op->cppDecl(); if (s.isEmpty()) s = CppSettings::operationDecl(); if ((index = s.indexOf("${(}")) != -1) s.insert(index + 4, (const char *)p); //[rageek] cast because QByteArray if ((index = s.indexOf("${type}")) != -1) s.insert(index + 7, " &"); op->set_CppDecl(s); s = op->cppDef(); if (s.isEmpty()) s = CppSettings::operationDef(); if ((index = s.indexOf("${(}")) != -1) s.insert(index + 4, (const char *)p); //[rageek] cast because QByteArray if ((index = s.indexOf("${type}")) != -1) s.insert(index + 7, " &"); op->set_CppDef(s); } }
void UmlClass::addCopy(bool cte) { TRACE_FUNCTION; UmlOperation * op = UmlOperation::create(this, name()); if (op == 0) UmlCom::trace("can't add copy contructor"); else { // to see that it is a copy constructor op->set_Stereotype("copy"); // add 'source' parameter UmlParameter param; param.name = "source"; param.dir = (cte) ? InputDirection : InputOutputDirection; param.type.type = this; op->addParameter(0, param); // add the parameter profile, and // remove the useless "${type} " mainly to remove the space QByteArray p = (cte) ? "const ${t0} & ${p0}" : "${t0} & ${p0}"; QByteArray s; int index; s = op->cppDecl(); if (s.isEmpty()) s = CppSettings::operationDecl(); if ((index = s.indexOf("${(}")) != -1) s.insert(index + 4, (const char *)p); //[rageek] cast because QByteArray if ((index = s.indexOf("${type} ")) != -1) s.remove(index, 8); op->set_CppDecl(s); s = op->cppDef(); if (s.isEmpty()) s = CppSettings::operationDef(); if ((index = s.indexOf("${(}")) != -1) s.insert(index + 4, (const char *)p); //[rageek] cast because QByteArray if ((index = s.indexOf("${type} ")) != -1) s.remove(index, 8); op->set_CppDef(s); } }
void UmlClass::add_inherited_opers(Vector * ops) { if (inherited_opers == 0) { const QVector<UmlItem*> ch = children(); inherited_opers = new Vector; for (int i = 0; i != ch.size(); i += 1) { switch (ch[i]->kind()) { case aRelation: { UmlRelation * rel = (UmlRelation *) ch[i]; aRelationKind k = rel->relationKind(); if ((k == aGeneralisation) || (k == aRealization)) rel->roleType()->add_inherited_opers(inherited_opers); } break; case anOperation: { UmlOperation * op = (UmlOperation *) ch[i]; if ((op->visibility() == PublicVisibility) && (op->name()[0] != '~') && (op->name() != name())) inherited_opers->addElement(op); } default: break; } } } if (ops != 0) for (unsigned i = 0; i != inherited_opers->size(); i += 1) if (! ops->contains(inherited_opers->elementAt(i))) ops->addElement(inherited_opers->elementAt(i)); unload(TRUE, FALSE); }
void UmlClass::addDestructor(bool virt) { TRACE_FUNCTION; UmlOperation * op = UmlOperation::create(this, "~" + name()); if (op == 0) UmlCom::trace("can't add destructor"); else { if (virt) op->set_isCppVirtual(TRUE); QByteArray s; int index; // remove the useless "${type} " mainly to remove the space s = op->cppDecl(); if (s.isEmpty()) s = CppSettings::operationDecl(); if ((index = s.indexOf("${type} ")) != -1) { s.remove(index, 8); op->set_CppDecl(s); } s = op->cppDef(); if (s.isEmpty()) s = CppSettings::operationDef(); if ((index = s.indexOf("${type} ")) != -1) { s.remove(index, 8); op->set_CppDef(s); } } }
UmlOperation * UmlOperation::already_exist(Class * container, const Q3CString & name, Q3ValueList<UmlParameter> & params) { const Q3PtrVector<UmlItem> & ch = container->get_uml()->UmlItem::children(); UmlItem ** v = ch.data(); UmlItem ** const vsup = v + ch.size(); Q3PtrList<UmlOperation> opers; for (; v != vsup; v += 1) if (((*v)->kind() == anOperation) && ((*v)->name() == name) && ((UmlOperation *) *v)->is_useless()) opers.append((UmlOperation *) *v); switch (opers.count()) { case 0: return 0; case 1: // suppose it is this one // even don't know if it is placed later in file return opers.getFirst(); default: break; } UmlOperation * op; Q3PtrList<UmlOperation> same_names; // search for operation having the same params name and number for (op = opers.first(); op != 0; op = opers.next()) { Q3ValueList<UmlParameter> ps = op->params(); Q3ValueList<UmlParameter>::ConstIterator it1; Q3ValueList<UmlParameter>::ConstIterator it2; bool same_type = TRUE; bool same_name = TRUE; for (it1 = params.begin(), it2 = ps.begin(); (it1 != params.end()) && (it2 != ps.end()); ++it1, ++it2) { const UmlParameter & p1 = *it1; const UmlParameter & p2 = *it2; if (p1.name != p2.name) { same_name = FALSE; break; } if (!p1.type.equal(p2.type)) same_type = FALSE; } if (same_name && (it1 == params.end()) && (it2 == ps.end())) { if (same_type) // perhaps several has the same number of param // and same param names and type because of [] // not managed here, suppose the right is this one return op; same_names.append(op); } } if (same_names.count() == 1) { // only one having the same number of param // and same param names (type changed) // suppose this one return same_names.getFirst(); } // suppose not find return 0; }
UmlOperation * UmlOperation::already_exist_from_id(Class * container, Q3CString & body) { const char * BodyPrefix = "// Bouml preserved body begin "; const char * BodyPostfix = "// Bouml preserved body end "; const int BodyPrefixLength = 30; const int BodyPostfixLength = 28; int index = body.find(BodyPrefix); if (index != -1) { const char * b1 = ((const char *) body) + index + BodyPrefixLength; char * b2; long id = strtol(b1, &b2, 16); if (b2 != (b1 + 8)) { QString err = "<font color =\"red\"> Error in " + Lex::filename() + " before line " + QString::number(Lex::line_number()) + " : invalid preserve body identifier</font><br>"; UmlCom::trace(err); throw 0; } if (*b2 == '\r') b2 += 1; if (*b2 == '\n') b2 += 1; else { QString err = "<font color =\"red\"> Error in " + Lex::filename() + " before line " + QString::number(Lex::line_number()) + " : invalid preserve body block, end of line expected</font><br>"; UmlCom::trace(err); throw 0; } const char * e; if (((e = strstr(b2, BodyPostfix)) == 0) || (strncmp(e + BodyPostfixLength, b1, 8) != 0)) { QString err = "<font color =\"red\"> Error in " + Lex::filename() + " before line " + QString::number(Lex::line_number()) + " : invalid preserve body block, wrong balanced</font><br>"; UmlCom::trace(err); throw 0; } while ((e != b2) && (e[-1] != '\n')) e -= 1; body = body.mid(b2 - (const char *) body, e - b2); UmlOperation * op = (UmlOperation *) UmlBaseItem::from_id((unsigned) id, anOperation); if (op != 0) { if (!op->is_useless()) { QString err = "<font color =\"red\"> Error in " + Lex::filename() + " before line " + QString::number(Lex::line_number()) + " : preserve body block identifier used twice</font><br>"; UmlCom::trace(err); throw 0; } if ((op->parent() == container->get_uml()) && // currently get/set are removed then recreated (op->getOf() == 0) && (op->setOf() == 0)) return op; } } return 0; }
bool UmlOperation::new_one(Class * container, const Q3CString & name, const Q3ValueList<FormalParameterList> & tmplts, const Q3CString & oper_templ, UmlTypeSpec & type, Q3CString str_actuals, UmlClass * first_actual_class, Q3CString type_def, aVisibility visibility, bool finalp, bool abstractp, bool staticp, bool nativep, bool strictfp, bool synchronizedp, const Q3CString & array, Q3CString comment, Q3CString description, Q3CString annotation #ifdef ROUNDTRIP , bool roundtrip, Q3PtrList<UmlItem> & expected_order #endif ) { // the "(" was read #ifdef TRACE QLOG_INFO() <<"OPERATION '" << name << "'\n"; #endif UmlClass * cl = container->get_uml(); UmlOperation * op; #ifdef ROUNDTRIP bool may_roundtrip = roundtrip && (!container->from_libp() || (visibility != PrivateVisibility)); UmlTypeSpec return_type; Q3ValueList<UmlParameter> params; Q3ValueList<UmlTypeSpec> exceptions; Q3CString body; if (may_roundtrip) #else if ( # ifdef REVERSE container->from_libp() && # endif (visibility == PrivateVisibility)) #endif op = 0; else { op = UmlBaseOperation::create(cl, name); if (op == 0) { JavaCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add operation <i>") + name + "</i> in <i>" + cl->name() + "</i></b></font><br>"); return FALSE; } #ifndef ROUNDTRIP # if defined(REVERSE) Statistic::one_operation_more(); # endif #endif } Q3CString def; #ifdef ROUNDTRIP if (may_roundtrip || (op != 0)) { #else if (op != 0) { op->set_Visibility(visibility); if (staticp) op->set_isClassMember(TRUE); if (abstractp) op->set_isAbstract(TRUE); if (finalp) op->set_isJavaFinal(TRUE); if (synchronizedp) op->set_isJavaSynchronized(TRUE); if (! annotation.isEmpty()) op->set_JavaAnnotations(annotation); #endif def = JavaSettings::operationDef(); int index; if (((index = def.find("${(}")) == -1) || ((index = def.find("${)}", index + 4)) == -1) || ((index = def.find("${throws}", index + 4)) == -1) || (def.find("${body}", index + 9) == -1) || ((index = def.find("${type}")) == -1)) { // use a definition where ${body] is not indented def = " ${comment}${@}${visibility}${final}${static}${abstract}${synchronized}${type} ${name}${(}${)}${throws}${staticnl}{\n${body}}\n"; index = def.find("${type}"); } if (!array.isEmpty()) def.insert(index + 7, (const char *)array); if (nativep) { def.insert(index, "native "); index += 7; // no body int index2 = def.find("${throws}", index+7); if (index2 != -1) { def.resize(index2 + 12); def[index2 + 9] = ';'; def[index2 + 10] = '\n'; } } if (strictfp) { def.insert(index, "strictfp "); index += 9; } if (! oper_templ.isEmpty()) def.insert(index, (const char *)(oper_templ + " ")); if (name == cl->name()) { // constructor, remove useless ${} if ((index = def.find("${static}")) != -1) def.remove(index, 9); if ((index = def.find("${type}")) != -1) def.remove(index, (((const char *) def)[index + 7] == ' ') ? 8 : 7); if ((index = def.find("${final}")) != -1) def.remove(index, 8); if ((index = def.find("${abstract}")) != -1) def.remove(index, 11); } if (type.type != 0) { UmlClass::manage_generic(def, type, str_actuals, "${type}"); #ifdef ROUNDTRIP return_type = type; #else op->set_ReturnType(type); #endif } else if (first_actual_class != 0) { #ifndef ROUNDTRIP UmlTypeSpec return_type; #endif return_type.type = first_actual_class; def.replace(def.find("${type}"), 7, type_def); #ifndef ROUNDTRIP op->set_ReturnType(return_type); #endif } else if (!type.explicit_type.isEmpty()) { // not a contructor #ifdef ROUNDTRIP return_type = type; #else op->set_ReturnType(type); #endif } } // parameters unsigned rank = 0; UmlParameter param; #ifdef ROUNDTRIP if (may_roundtrip) while (read_param(container, rank++, tmplts, param, def, FALSE)) params.append(param); else #endif while (read_param(container, rank, tmplts, param, def, op == 0)) { if ((op != 0) && ! op->addParameter(rank, param)) { JavaCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add param <i>") + name + "</i> in <i>" + cl->name() + "</i></b></font><br>"); # ifdef TRACE QLOG_INFO() <<"ERROR cannot add param '" << param.name << "' type '" << param.type.Type() << '\n'; # endif return FALSE; } rank += 1; } Q3CString s = Lex::read_word(); if (!s.isEmpty() && (*((const char *) s) == '[')) { #ifdef ROUNDTRIP if (may_roundtrip) #else if (op != 0) #endif // do not place it at the same place def.insert(def.find("${type}") + 7, (const char *)s); s = Lex::read_word(); } if (s.isEmpty()) { Lex::premature_eof(); return FALSE; } if (s == "throws") { // throws rank = 0; for (;;) { if ((s = Lex::read_word()).isEmpty()) { Lex::premature_eof(); return FALSE; } #ifdef ROUNDTRIP if (may_roundtrip) { UmlTypeSpec typespec; container->compute_type(s, typespec, tmplts); exceptions.append(typespec); } else #endif if (op != 0) { UmlTypeSpec typespec; container->compute_type(s, typespec, tmplts); if (! op->addException(rank++, typespec)) { # ifdef TRACE QLOG_INFO() <<"cannot add exception " << s << '\n'; # endif return FALSE; } } if (((s = Lex::read_word()) == "{") || (s == ";")) break; if (s != ",") { Lex::error_near(s, " ',' expected"); return FALSE; } } } // definition if (abstractp || nativep || (cl->stereotype() == "interface") || (cl->stereotype() == "@interface")) { if ((s == "default") && (cl->stereotype() == "@interface")) { int index = def.find("${)}"); Lex::mark(); s = Lex::read_word(); if (s == "{") { int level = 1; char c; for (;;) { if ((c = Lex::read_word_bis()) == 0) return FALSE; else if (c == '{') level += 1; else if ((c == '}') && (--level == 0)) break; } s = Lex::region(); } def.insert(index + 4, (const char *)(" default" + s)); s = Lex::read_word(); } if (s != ";") { Lex::error_near(s, " ';' expected"); return FALSE; } #ifdef REVERSE # ifndef ROUNDTRIP if ((op != 0) && !container->from_libp()) op->set_JavaBody(0); # endif #endif } else if (s != "{") { Lex::error_near(s, " '{' expected"); return FALSE; } else { Lex::mark(); // goto the end of the body #ifndef ROUNDTRIP Q3CString body; #endif int level = 1; // '{' already read char c; for (;;) { if ((c = Lex::read_word_bis()) == 0) return FALSE; else if (c == '{') level += 1; else if ((c == '}') && (--level == 0)) break; } #ifdef REVERSE if ( # ifdef ROUNDTRIP may_roundtrip || (op != 0) # else (op != 0) && !container->from_libp() # endif ) { body = Lex::region(); body.truncate(body.length() - 1); // remove } // remove fist \n if (*((const char *) body) == '\n') body.remove(0, 1); // remove last spaces and tabs int ln = body.length(); while (ln && ((body[ln - 1] == ' ') || (body[ln - 1] == '\t'))) ln -= 1; body.truncate(ln); if (!body.isEmpty() && (body[ln - 1] != '\n')) body += "\n"; # ifndef ROUNDTRIP op->set_JavaBody(body); op->set_JavaContextualBodyIndent(FALSE); # endif } #endif } #ifdef ROUNDTRIP if (may_roundtrip) { if (((op = already_exist_from_id(container, body)) != 0) || ((op = already_exist(container, name, params)) != 0)) { // update already existing operation op->set_usefull(); { // remove \r in case of preserve body Q3CString current_body = op->javaBody(); int index = 0; while ((index = current_body.find('\r', index)) != -1) current_body.remove(index, 1); if (nequal(current_body, body)) { container->set_updated(); op->set_JavaBody(body); op->set_JavaContextualBodyIndent(FALSE); } } if (op->visibility() != visibility) { container->set_updated(); op->set_Visibility(visibility); } if (op->isClassMember() != staticp) { container->set_updated(); op->set_isClassMember(staticp); } if (op->isAbstract() != abstractp) { container->set_updated(); op->set_isAbstract(abstractp); } if (op->isJavaFinal() != finalp) { container->set_updated(); op->set_isJavaFinal(finalp); } if (op->isJavaSynchronized() != synchronizedp) { container->set_updated(); op->set_isJavaSynchronized(synchronizedp); } if (nequal(op->javaAnnotations(), annotation)) { container->set_updated(); op->set_JavaAnnotations(annotation); } if (!op->returnType().equal(return_type)) { container->set_updated(); op->set_ReturnType(return_type); } Q3ValueList<UmlParameter>::Iterator itp1; const Q3ValueList<UmlParameter> old_params = op->params(); Q3ValueList<UmlParameter>::ConstIterator itp2; for (rank = 0, itp1 = params.begin(), itp2 = old_params.begin(); (itp1 != params.end()) && (itp2 != old_params.end()); ++itp1, ++itp2, rank += 1) { UmlParameter & p1 = *itp1; const UmlParameter & p2 = *itp2; if ((p1.name != p2.name) || nequal(p1.default_value, p2.default_value) || !p1.type.equal(p2.type)) { if (p1.dir != InputDirection) p1.dir = p2.dir; op->replaceParameter(rank, p1); container->set_updated(); } else if ((p1.dir == InputDirection) && (p2.dir != InputDirection)) { op->replaceParameter(rank, p1); container->set_updated(); } } if (itp1 != params.end()) { // have missing params container->set_updated(); do { op->addParameter(rank, *itp1); itp1++; rank += 1; } while (itp1 != params.end()); } else if (itp2 != old_params.end()) { // have extra params container->set_updated(); do { op->removeParameter(rank); itp2++; } while (itp2 != old_params.end()); } Q3ValueList<UmlTypeSpec>::ConstIterator ite1; const Q3ValueList<UmlTypeSpec> old_exceptions = op->exceptions(); Q3ValueList<UmlTypeSpec>::ConstIterator ite2; for (rank = 0, ite1 = exceptions.begin(), ite2 = old_exceptions.begin(); (ite1 != exceptions.end()) && (ite2 != old_exceptions.end()); ++ite1, ++ite2, rank += 1) { const UmlTypeSpec & e1 = *ite1; if (!e1.equal(*ite2)) { op->replaceException(rank, e1); container->set_updated(); } } if (ite1 != exceptions.end()) { // have missing exceptions container->set_updated(); do { op->addException(rank, *ite1); ite1++; rank += 1; } while (ite1 != exceptions.end()); } else if (ite2 != old_exceptions.end()) { // have extra exceptions container->set_updated(); do { op->removeException(rank); ite2++; } while (ite2 != old_exceptions.end()); } if (neq(def, op->javaDecl())) { container->set_updated(); op->set_JavaDecl(def); } Lex::clear_comments(); // params & body comments Lex::finish_line(); if (def.find("${description}") != -1) { if (nequal(op->description(), description)) { container->set_updated(); op->set_Description(description); } } else if (nequal(op->description(), Lex::simplify_comment(comment))) { op->set_Description(comment); // comment was set container->set_updated(); } expected_order.append(op); return TRUE; } // operation doesn't yet exist container->set_updated(); op = UmlBaseOperation::create(cl, name); if (op == 0) { JavaCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add operation <i>") + name + "</i> in <i>" + cl->name() + "</i></b></font><br>"); throw 0; } expected_order.append(op); Q3ValueList<UmlParameter>::ConstIterator itp; for (rank = 0, itp = params.begin(); itp != params.end(); ++itp) op->addParameter(rank++, *itp); Q3ValueList<UmlTypeSpec>::ConstIterator ite; for (rank = 0, ite = exceptions.begin(); ite != exceptions.end(); ++ite) op->addException(rank++, *ite); } if (op != 0) { op->set_JavaContextualBodyIndent(FALSE); op->set_Visibility(visibility); if (staticp) op->set_isClassMember(TRUE); if (abstractp) op->set_isAbstract(TRUE); if (finalp) op->set_isJavaFinal(TRUE); if (synchronizedp) op->set_isJavaSynchronized(TRUE); if (! annotation.isEmpty()) op->set_JavaAnnotations(annotation); op->set_JavaBody(body); op->set_ReturnType(return_type); if (def != JavaSettings::operationDef()) op->set_JavaDecl(def); } #else if ((op != 0) && (def != JavaSettings::operationDef())) op->set_JavaDecl(def); #endif Lex::clear_comments(); // params & body comments Lex::finish_line(); if (!comment.isEmpty()) if (op != 0) op->set_Description((def.find("${description}") != -1) ? description : Lex::simplify_comment(comment)); return TRUE; } bool UmlOperation::read_param(Class * container, unsigned rank, const Q3ValueList<FormalParameterList> & tmplts, UmlParameter & param, Q3CString & def, bool bypass) { #ifdef TRACE QLOG_INFO() <<"UmlOperation::manage_param " << rank << "\n"; #endif bool finalp = FALSE; bool in = FALSE; bool ellipsis = FALSE; Q3CString array; bool type_read = FALSE; Q3ValueList<UmlTypeSpec> actuals; Q3CString str_actuals; Q3CString annotation; param.name = param.default_value = 0; Q3CString s = Lex::read_word(); #ifdef TRACE QLOG_INFO() <<"commence par " << s << '\n'; #endif if (s == ")") return FALSE; for (;;) { if (s.isEmpty()) { Lex::premature_eof(); return FALSE; } else if (s == "final") finalp = TRUE; else if ((s == "void") || (s == "byte") || (s == "char") || (s == "short") || (s == "int") || (s == "long") || (s == "float") || (s == "double")) { if (type_read) { Lex::error_near(s); return FALSE; } param.type.type = 0; param.type.explicit_type = s; type_read = TRUE; in = TRUE; } else if ((s == ")") || (s == ",")) { if (param.name.isEmpty() && !type_read) { Lex::error_near(s); return FALSE; } if (s == ")") Lex::unread_word(s); if (! bypass) { param.dir = (finalp || in) ? InputDirection : InputOutputDirection; Q3CString s; if (rank != 0) s = ", "; if (! annotation.isEmpty()) s += annotation + " "; if (finalp) s += "final "; if ((param.type.type != 0) && !param.type.explicit_type.isEmpty()) s += param.type.explicit_type; else { s += "${t"; s += Q3CString().setNum(rank); s += "}"; if (param.type.type != 0) s += str_actuals; } s += array; s += (ellipsis) ? " ... ${p": " ${p"; s += Q3CString().setNum(rank); s += "}"; def.insert(def.find("${)}"), // cannot be -1 (const char *)s); } return TRUE; } else if (Lex::identifierp(s)) { if (!type_read) { while (s.at(s.length() - 1) == '.') { // type on several lines, managed in this case Q3CString s2 = Lex::read_word(); if (Lex::identifierp(s2)) s += s2; else { Lex::error_near(s, " identifier expected"); return FALSE; } } #ifdef TRACE QLOG_INFO() <<"type = '" << s << "...'\n"; #endif if (! bypass) { Q3CString dummy; container->read_type(param.type, 0, tmplts, 0, str_actuals, s, 0, dummy, dummy); if (param.type.explicit_type == "String") // at least for it ! in = TRUE; } else Lex::bypass_type(s); type_read = TRUE; } else if (param.name.isEmpty()) { if (s == "...") ellipsis = TRUE; else { param.name = s; #ifdef TRACE QLOG_INFO() <<"name = '" << param.name << "'\n"; #endif } } else { Lex::error_near(s); #ifdef TRACE QLOG_INFO() <<"ERROR '" << s << "' alors qu a deja le type et le nom '" << param.name << "'\n"; #endif return FALSE; } } else if (*((const char *) s) == '@') annotation = s; else if (*((const char *) s) == '[') { in = FALSE; array = s; } else { Lex::error_near(s); #ifdef TRACE QLOG_INFO() <<"ERROR : '" << s << "'\n"; #endif return FALSE; } s = Lex::read_word(); } }
void UmlTransition::generate(UmlClass * machine, UmlClass * anystate, UmlState * state) { if (_already_managed) return; Q3CString s = triggerName(); // group transitions having the same trigger const Q3PtrVector<UmlItem> ch = parent()->children(); unsigned index = ch.findRef(this); Q3PtrList<UmlTransition> trs; UmlTransition * tr_no_guard = 0; if (cppGuard().isEmpty()) tr_no_guard = this; else trs.append(this); while (++index != ch.count()) { if ((ch[index]->kind() == aTransition) && (((UmlTransition *) ch[index])->triggerName() == s)) { if (!((UmlTransition *) ch[index])->cppGuard().isEmpty()) trs.append((UmlTransition *) ch[index]); else if (tr_no_guard != 0) { UmlCom::trace("Error : several transitions from '" + parent()->name() + "' don't have guard"); throw 0; } else tr_no_guard = (UmlTransition *) ch[index]; ((UmlTransition *) ch[index])->_already_managed = TRUE; } } if (tr_no_guard != 0) // place it at end trs.append(tr_no_guard); // made the trigger UmlOperation * trg = state->assocClass()->trigger(s, machine, anystate); Q3CString body; if (s == "create") { // manage entry if (!state->cppEntryBehavior().isEmpty()) body = " _doentry(stm);\n"; } if (!state->cppDoActivity().isEmpty()) // state do activity before each event except create body += " _do(stm);\n"; bool completion = (s == "_completion"); if (!completion && state->isLeaf() && state->hasCompletion()) // manage completion body += " if (_completion(stm)) return;\n"; UmlTransition::generate(trs, machine, anystate, state, body, " ", completion); trg->set_CppBody(body); }
void UmlState::html(Q3CString pfix, unsigned int rank, unsigned int level) { define(); chapter((parent()->kind() == aClassView) ? "StateMachine" : "State", pfix, rank, "state", level); Q3CString s = description(); if (!s.isEmpty()) { fw.write("<p>"); writeq(description()); fw.write("<br /></p>"); } UmlState * ref = reference(); if (ref != 0) { fw.write("<p>References "); ref->write(); fw.write("</p>"); } else { if (isActive()) fw.write("<p>Active state</p>\n"); UmlOperation * beh = specification(); if (beh != 0) { fw.write("<p>Implements "); beh->write(); fw.write("</p>"); } Q3CString scpp, sjava; s = entryBehavior(); scpp = cppEntryBehavior(); sjava = javaEntryBehavior(); if (!s.isEmpty() || !scpp.isEmpty() || !sjava.isEmpty()) { fw.write("<p>Entry Behavior :</p><ul>"); if (!s.isEmpty()) { fw.write("<li>OCL : <pre>\n"); writeq(s); fw.write("</pre></li>"); } if (!scpp.isEmpty()) { fw.write("<li>C++ : <pre>\n"); writeq(scpp); fw.write("</pre></li>"); } if (!sjava.isEmpty()) { fw.write("<li>Java : <pre>\n"); writeq(sjava); fw.write("</pre></li>"); } fw.write("</ul>"); } s = exitBehavior(); scpp = cppExitBehavior(); sjava = javaExitBehavior(); if (!s.isEmpty() || !scpp.isEmpty() || !sjava.isEmpty()) { fw.write("<p>Exit Behavior :</p><ul>"); if (!s.isEmpty()) { fw.write("<li>OCL : <pre>\n"); writeq(s); fw.write("</pre></li>"); } if (!scpp.isEmpty()) { fw.write("<li>C++ : <pre>\n"); writeq(scpp); fw.write("</pre></li>"); } if (!sjava.isEmpty()) { fw.write("<li>Java : <pre>\n"); writeq(sjava); fw.write("</pre></li>"); } fw.write("</ul>"); } s = doActivity(); scpp = cppDoActivity(); sjava = javaDoActivity(); if (!s.isEmpty() || !scpp.isEmpty() || !sjava.isEmpty()) { fw.write("<p>Do activity :</p><ul>"); if (!s.isEmpty()) { fw.write("<li>OCL : <pre>\n"); writeq(s); fw.write("</pre></li>"); } if (!scpp.isEmpty()) { fw.write("<li>C++ : <pre>\n"); writeq(scpp); fw.write("</pre></li>"); } if (!sjava.isEmpty()) { fw.write("<li>Java : <pre>\n"); writeq(sjava); fw.write("</pre></li>"); } fw.write("</ul>"); } } UmlStateDiagram * d = associatedDiagram(); if (d != 0) { fw.write("<p>Diagram : "); d->write(); fw.write("</p>"); } write_properties(); write_children(pfix, rank, level); unload(FALSE, FALSE); }
void UmlOperation::roundtrip(const char * path, aLanguage who) { char * s = read_file(path); if (s != 0) { char * p1 = s; char * p2; WrapperStr(UmlOperation::*get_body)(); bool (UmlOperation::*set_body)(const char * s); bool (UmlOperation::*set_contextualbodyindent)(bool v); const char * prefix; const char * postfix; switch (who) { case cppLanguage: get_body = &UmlOperation::cppBody; set_body = &UmlOperation::set_CppBody; set_contextualbodyindent = &UmlOperation::set_CppContextualBodyIndent; prefix = BodyPrefix; postfix = BodyPostfix; break; case javaLanguage: get_body = &UmlOperation::javaBody; set_body = &UmlOperation::set_JavaBody; set_contextualbodyindent = &UmlOperation::set_JavaContextualBodyIndent; prefix = BodyPrefix; postfix = BodyPostfix; break; case phpLanguage: get_body = &UmlOperation::phpBody; set_body = &UmlOperation::set_PhpBody; set_contextualbodyindent = &UmlOperation::set_PhpContextualBodyIndent; prefix = BodyPrefix; postfix = BodyPostfix; break; default: // python get_body = &UmlOperation::pythonBody; set_body = &UmlOperation::set_PythonBody; set_contextualbodyindent = &UmlOperation::set_PythonContextualBodyIndent; prefix = BodyPythonPrefix; postfix = BodyPythonPostfix; } while ((p2 = strstr(p1, prefix)) != 0) { p2 += BodyPrefixLength; char * body; long id = strtol(p2, &body, 16); if (body != (p2 + 8)) { UmlCom::trace(WrapperStr("<font color =\"red\"> Error in ") + path + linenumber(s, p2 - BodyPrefixLength) + " : invalid preserve body identifier</font><br>"); UmlCom::bye(n_errors() + 1); UmlCom::fatal_error("read_bodies 1"); } if (*body == '\r') body += 1; if (*body == '\n') body += 1; else { UmlCom::trace(WrapperStr("<font color =\"red\"> Error in ") + path + linenumber(s, p2 - BodyPrefixLength) + " : invalid preserve body block, end of line expected</font><br>"); UmlCom::bye(n_errors() + 1); UmlCom::fatal_error("read_bodies 2"); } UmlOperation * op = (UmlOperation *) UmlBaseItem::from_id((unsigned) id, anOperation); if (op == 0) { QString n("%1"); n.arg(QString::number((unsigned) id)); UmlCom::trace(WrapperStr("<font color =\"red\"> Error in ") + path + linenumber(s, p2 - BodyPrefixLength) + " : invalid operation id " + n + "</font><br>"); UmlCom::bye(n_errors() + 1); UmlCom::fatal_error("read_bodies 3"); return; } if (((p1 = strstr(body, postfix)) == 0) || (strncmp(p1 + BodyPostfixLength, p2, 8) != 0)) { UmlCom::trace(WrapperStr("<font color =\"red\"> Error in ") + path + linenumber(s, p2 - BodyPrefixLength) + " : invalid preserve body block, wrong balanced</font><br>"); UmlCom::bye(n_errors() + 1); UmlCom::fatal_error("read_bodies 4"); } p2 = p1; while ((p2 != body) && (p2[-1] != '\n')) p2 -= 1; char c = *p2; *p2 = 0; WrapperStr previous = (op->*get_body)(); if (!op->isBodyGenerationForced() && (body != previous)) { if (!(op->*set_body)(body)) { write_trace_header(); UmlCom::trace(" <font color=\"red\"><b>cannot update body of <i>" + op->name() + ((op->isWritable()) ? "</i>, it is probably deleted</b></font><br>" : "</i>, it is read-only</b></font><br>")); incr_error(); } else { (op->*set_contextualbodyindent)(FALSE); write_trace_header(); UmlCom::trace(" update body of <i>" + op->name() + "</i><br>"); } } else if (verbose()) { write_trace_header(); UmlCom::trace(" body of <i>" + op->name() + "</i> unchanged<br>"); } *p2 = c; p1 += BodyPostfixLength + 8; } delete [] s; } }
void UmlOperation::import(File & f, UmlClass * parent) { QByteArray s; if (f.read(s) != STRING) f.syntaxError(s, "operations's name"); QByteArray id; QByteArray ste; QByteArray doc; QHash<QByteArray, QByteArray*> prop; QByteArray s2; int k; do { k = f.readDefinitionBeginning(s2, id, ste, doc, prop); } while (id.isEmpty()); UmlOperation * x; if (scanning) { QByteArray name; if (s.left(8) != "operator") name = (s.at(0) == '~') ? ("~" + legalName(s.mid(1))) : legalName(s); else name = s; if ((x = UmlBaseOperation::create(parent, name)) == 0) { UmlCom::trace("<br>cannot create operation '" + s + "' in " + parent->fullName()); throw 0; } newItem(x, id); if (!ste.isEmpty()) { bool managed = FALSE; QStringList l = QString(ste).split(","); for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) { if ((*it) == "const") { managed = TRUE; x->set_isCppConst(TRUE); } else if ((*it) == "abstract") { managed = TRUE; x->set_isAbstract(TRUE); x->set_isCppVirtual(TRUE); } else if ((*it) == "virtual") { managed = TRUE; x->set_isCppVirtual(TRUE); } else if ((*it) == "static") { managed = TRUE; x->set_isClassMember(TRUE); } } if (!managed) x->set_Stereotype(ste); } if (!doc.isEmpty()) x->set_Description(doc); } else if ((x = (UmlOperation *) findItem(id, anOperation)) == 0) { UmlCom::trace("<br>unknown operation '" + s + "' in " + parent->fullName()); throw 0; } else { switch (((UmlClass *) x->parent())->language()) { case Cplusplus: case AnsiCplusplus: case VCplusplus: x->cplusplus(prop); break; case Oracle8: x->oracle8(prop); break; case Corba: x->corba(prop); break; case Java: x->java(prop); break; default: break; } x->setProperties(prop); } f.unread(k, s2); x->import(f); }
UmlOperation * UmlOperation::cpp2Python(UmlClass * python, UmlClass * cpp, const char * cppname, const char * pythonname) { if (pythonname == 0) pythonname = cppname; UmlOperation * from = cpp->get_operation(cppname); if (from == 0) { QCString err = QCString("cannot find operation '") + cppname + QCString("' in class '") + cpp->name() + QCString("'<br>\n"); UmlCom::trace(err); throw 0; } UmlOperation * to = UmlBaseOperation::create(python, pythonname); if (to == 0) { QCString err = QCString("cannot create operation '") + pythonname + QCString("' in class '") + python->name() + QCString("'<br>\n"); UmlCom::trace(err); throw 0; } UmlCom::trace("add operation " + python->name() + "::" + pythonname + "<br>\n"); to->set_Description(::cpp2Python(from->description())); to->set_ReturnType(from->returnType()); to->set_isClassMember(from->isClassMember()); to->set_Visibility(from->visibility()); to->set_CppVisibility(from->cppVisibility()); const QValueList<UmlParameter> params = from->params(); unsigned index; for (index = 0; index != params.count(); index += 1) to->addParameter(index, params[index]); const QValueList<UmlTypeSpec> exceptions = from->exceptions(); for (index = 0; index != exceptions.count(); index += 1) to->addException(index, exceptions[index]); to->set_isCppVirtual(from->isCppVirtual()); to->set_isCppConst(from->isCppConst()); to->set_isCppInline(from->isCppInline()); to->set_CppDecl(::cpp2Python(from->cppDecl())); to->set_CppDef(::cpp2Python(from->cppDef())); to->set_CppBody(::cpp2Python(from->cppBody())); to->set_isJavaFinal(from->isJavaFinal()); to->set_JavaDef(from->javaDef()); to->set_JavaBody(::cpp2Python(from->javaBody())); return to; }
bool UmlOperation::new_one(Class * container, aVisibility visibility, bool finalp, bool abstractp, bool staticp, Q3CString comment, Q3CString description) { // 'function' was read, it is followed by : // ['&'] name'(' {'array' | <classname>] ['&'] '$'<varname> ['=' <value>]}* ')' '{' ... '}' Q3CString s = Lex::read_word(); bool refp; if (s == "&") { refp = TRUE; s = Lex::read_word(); } else refp = FALSE; if (s.isEmpty()) { Lex::premature_eof(); return FALSE; } Q3CString name = s; #ifdef TRACE QLOG_INFO() <<"OPERATION '" << name << "'\n"; #endif s = Lex::read_word(); if (s != "(") { Lex::syntax_error("'(' expected rather than '" + s + "'"); return FALSE; } UmlClass * cl = container->get_uml(); UmlOperation * op; #ifndef REVERSE if (visibility == PrivateVisibility) op = 0; else #endif { op = UmlBaseOperation::create(cl, name); if (op == 0) { PhpCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add operation <i>") + name + "</i> in <i>" + cl->name() + "</i></b></font><br>"); return FALSE; } #ifdef REVERSE Statistic::one_operation_more(); #endif } Q3CString def; if (op != 0) { op->set_Visibility(visibility); if (staticp) op->set_isClassMember(TRUE); if (finalp) op->set_isPhpFinal(TRUE); def = PhpSettings::operationDef(); int index; if (((index = def.find("${(}")) == -1) || (def.find("${)}", index + 4) == -1) || ((index = def.find("${name}")) == -1) || (def.find("${body}") == -1)) { // use a definition where ${body] is not indented def = " ${comment}${final}${visibility}${abstract}${static}function ${name}${(}${)}\n{\n ${body}}\n"; index = def.find("${name}"); } if (refp) def.insert(index, "&"); if ((name == cl->name()) || (name == "__construct")) { // constructor, remove useless ${} if ((index = def.find("${static}")) != -1) def.remove(index, 9); if ((index = def.find("${final}")) != -1) def.remove(index, 8); if ((index = def.find("${abstract}")) != -1) def.remove(index, 11); } if (abstractp) { op->set_isAbstract(TRUE); def = def.left(def.find("${)}") + 4) + ";"; } } // parameters unsigned rank = 0; UmlParameter param; while (read_param(container, rank, param, def, op == 0)) { if ((op != 0) && ! op->addParameter(rank++, param)) { PhpCatWindow::trace(Q3CString("<font face=helvetica><b>cannot add param <i>") + name + "</i> in <i>" + cl->name() + "</i></b></font><br>"); #ifdef TRACE QLOG_INFO() <<"ERROR cannot add param '" << param.name << '\n'; #endif return FALSE; } } s = Lex::read_word(); if (s.isEmpty()) { Lex::premature_eof(); return FALSE; } // definition if (abstractp || (cl->stereotype() == "interface")) { if (s != ";") { Lex::error_near(s); return FALSE; } #ifdef REVERSE if (op != 0) op->set_PhpBody(0); #endif } else if (s != "{") { Lex::error_near(s); return FALSE; } else { Lex::mark(); // goto the end of the body char c; int level = 1; // '{' already read for (;;) { if ((c = Lex::read_word_bis()) == 0) return FALSE; else if (c == '{') level += 1; else if ((c == '}') && (--level == 0)) break; } #ifdef REVERSE if (op != 0) { Q3CString e = Lex::region(); e.truncate(e.length() - 1); // remove } // remove fist \n if (*((const char *) e) == '\n') e.remove(0, 1); // remove last spaces and tabs int ln = e.length(); while (ln && ((e[ln - 1] == ' ') || (e[ln - 1] == '\t'))) ln -= 1; e.truncate(ln); op->set_PhpBody(e); op->set_PhpContextualBodyIndent(FALSE); } #endif } if ((op != 0) && (def != op->phpDecl())) op->set_PhpDecl(def); Lex::clear_comments(); // params & body comments Lex::finish_line(); if ((op != 0) && !comment.isEmpty()) { s = (def.find("${description}") != -1) ? description : comment; UmlTypeSpec t; int index1; if (! (t.explicit_type = value_of(s, "@return", index1)).isEmpty()) { op->set_ReturnType(t); s.replace(index1, t.explicit_type.length(), "${type}"); } Q3ValueList<UmlParameter> l = op->params(); unsigned nparams = l.count(); if (nparams != 0) { Q3CString varname; int index2; char xn[16]; index1 = 0; rank = 0; while (!((t.explicit_type = value_of(s, "@param", index1, varname, index2)) .isEmpty())) { if (varname.isEmpty() || (varname[0] != '$')) { if (rank < nparams) { UmlParameter & p = l[rank]; p.type = t; op->replaceParameter(rank, p); } } else { varname = varname.mid(1); Q3ValueList<UmlParameter>::Iterator it; for (it = l.begin(), rank = 0; it != l.end(); ++it, rank += 1) { if ((*it).name == varname) { (*it).type = t; op->replaceParameter(rank, *it); sprintf(xn, "${p%d}", rank); s.replace(index2, varname.length() + 1, xn); break; } } } sprintf(xn, "${t%d}", rank++); s.replace(index1, t.explicit_type.length(), xn); } } op->set_Description(s); } return TRUE; }