void UmlClass::extend(WrapperStr mcl) { if (parent()->parent()->kind() != aPackage) return; int index = mcl.find('#'); if (index == -1) return; WrapperStr path = mcl.left(index); const char * defltpath0 = "http://schema.omg.org/spec/UML/2.0/uml.xml"; const char * defltpath1 = "http://schema.omg.org/spec/UML/2.1/uml.xml"; bool dflt = ((path == defltpath0) || (path == defltpath1)); mcl = mcl.mid(index + 1); static Q3PtrList<UmlClass> metaclasses; Q3PtrListIterator<UmlClass> it(metaclasses); UmlClass * metacl = UmlClass::get(mcl, 0); WrapperStr s; if ((metacl == 0) || (metacl->stereotype() != "metaclass") || !((dflt) ? (!metacl->propertyValue("metaclassPath", s) || (s == defltpath0) || (s == defltpath1)) : (metacl->propertyValue("metaclassPath", s) && (path == s)))) { metacl = 0; if (dflt) { for (; (metacl = it.current()) != 0; ++it) { if (!strcmp(mcl, metacl->name()) && (!metacl->propertyValue("metaclassPath", s) || (s == defltpath0) || (s == defltpath1))) break; } } else { for (; (metacl = it.current()) != 0; ++it) { if (!strcmp(mcl, metacl->name()) && metacl->propertyValue("metaclassPath", s) && (path == s)) break; } } if (metacl == 0) { metacl = addMetaclass(mcl, (dflt) ? 0 : (const char *)path); //[rageek] different types for ? : metaclasses.append(metacl); } } UmlRelation::create(aDirectionalAssociation, this, metacl); }
bool UmlAttribute::new_one(Class * container, const WrapperStr & name, UmlTypeSpec typespec, aVisibility visibility, bool staticp, bool finalp, bool transientp, bool volatilep, const WrapperStr & array, const WrapperStr & value, WrapperStr comment, WrapperStr description, WrapperStr annotation #ifdef ROUNDTRIP , bool roundtrip, QList<UmlItem *> & expected_order #endif ) { #ifdef TRACE QLOG_INFO() << "ATTRIBUTE '" << name << "'\n"; #endif if ( #ifdef REVERSE container->from_libp() && ( #endif visibility == PrivateVisibility #ifdef REVERSE ) #endif ) { Lex::finish_line(); Lex::clear_comments(); return TRUE; } UmlClass * cl = container->get_uml(); UmlAttribute * at; #ifdef ROUNDTRIP bool created; if (!roundtrip || ((at = search_attr(container, name)) == 0)) { #endif at = UmlBaseAttribute::create(cl, name); if (at == 0) { JavaCatWindow::trace(WrapperStr("<font face=helvetica><b>cannot add attribute <i>") + name + "</i> in <i>" + cl->name() + "</i></b></font><br>"); return FALSE; } #ifdef REVERSE # ifndef ROUNDTRIP Statistic::one_attribute_more(); # else if (roundtrip) container->set_updated(); created = TRUE; } else created = FALSE; # endif #endif Lex::finish_line(); comment = Lex::get_comments(comment); description = Lex::get_description(description); WrapperStr decl = JavaSettings::attributeDecl(""); int index = decl.find("${type}"); if ((index == -1) || (decl.find("${name}") == -1)) { decl = " ${comment}${@}${visibility}${static}${final}${transient}${volatile}${type} ${name}${value};"; index = decl.find("${type}"); } #ifdef ROUNDTRIP if (roundtrip && !created) { if (decl.find("${description}") != -1) { if (nequal(at->description(), description)) { at->set_Description(description); container->set_updated(); } } else if (nequal(at->description(), Lex::simplify_comment(comment))) { at->set_Description(comment); // comment was set container->set_updated(); } if (at->isReadOnly() != finalp) { at->set_isReadOnly(finalp); container->set_updated(); } if (at->isJavaTransient() != transientp) { at->set_isJavaTransient(transientp); container->set_updated(); } if (at->isVolatile() != volatilep) { at->set_isVolatile(volatilep); container->set_updated(); } if (at->isClassMember() != staticp) { at->set_isClassMember(staticp); container->set_updated(); } if (!array.isEmpty()) decl.insert(index + 7, "${multiplicity}"); if (neq(at->multiplicity(), array)) { at->set_Multiplicity(array); container->set_updated(); } WrapperStr v = at->defaultValue(); if (!v.isEmpty() && (((const char *) v)[0] == '=')) v = v.mid(1); if (nequal(v, value)) { at->set_DefaultValue(value); container->set_updated(); } if (nequal(at->javaAnnotations(), annotation)) { at->set_JavaAnnotations(annotation); container->set_updated(); } WrapperStr stereotype; bool force_ste = FALSE; if (cl->stereotype() == "enum") { stereotype = "attribute"; force_ste = TRUE; } else if (typespec.type == 0) { WrapperStr t = typespec.explicit_type; int index2; if (!t.isEmpty() && (t.at(t.length() - 1) == ">") && ((index2 = t.find('<')) > 0)) { stereotype = t.left(index2); typespec.explicit_type = // may be a,b ... t.mid(index2 + 1, t.length() - 2 - index2); decl.replace(index, 7, "${stereotype}<${type}>"); force_ste = TRUE; } } if (at->visibility() != visibility) { at->set_Visibility(visibility); container->set_updated(); } if (neq(at->stereotype(), stereotype)) { WrapperStr jst; if (! at->stereotype().isEmpty()) jst = JavaSettings::relationAttributeStereotype(at->stereotype()); if ((force_ste) ? (jst != stereotype) : (jst == "attribute")) { at->set_Stereotype(stereotype); container->set_updated(); } } if (neq(at->javaDecl(), decl)) { at->set_JavaDecl(decl); container->set_updated(); } if (!at->type().equal(typespec)) { at->set_Type(typespec); container->set_updated(); } at->set_usefull(); expected_order.append(at); } else { #endif if (!comment.isEmpty()) at->set_Description((decl.find("${description}") != -1) ? description : Lex::simplify_comment(comment)); if (finalp) at->set_isReadOnly(TRUE); if (transientp) at->set_isJavaTransient(TRUE); if (volatilep) at->set_isVolatile(TRUE); if (staticp) at->set_isClassMember(TRUE); if (!array.isEmpty()) { decl.insert(index + 7, "${multiplicity}"); at->set_Multiplicity(array); } if (! value.isEmpty()) at->set_DefaultValue(value); if (! annotation.isEmpty()) at->set_JavaAnnotations(annotation); if ((typespec.type == 0) && (cl->stereotype() != "enum")) { WrapperStr t = typespec.explicit_type; int index2 = 0; if (!t.isEmpty() && (t.at(t.length() - 1) == ">") && ((index2 = t.find('<')) > 0)) { at->set_Stereotype(t.left(index2)); typespec.explicit_type = // may be a,b ... t.mid(index2 + 1, t.length() - 2 - index2); decl.replace(index, 7, "${stereotype}<${type}>"); } } at->set_Visibility(visibility); if (cl->stereotype() == "enum") { at->set_JavaDecl(decl); at->set_Stereotype("attribute"); } else if (decl != JavaSettings::attributeDecl("")) at->set_JavaDecl(decl); at->set_Type(typespec); #ifdef ROUNDTRIP if (roundtrip) expected_order.append(at); } #endif return TRUE; }
UmlClass * UmlClass::auxilarily_typedef(const WrapperStr & base #ifdef REVERSE , bool libp # ifdef ROUNDTRIP , bool container_roundtrip , QList<UmlItem *> & container_expected_order # endif #endif ) { WrapperStr typedef_decl = CppSettings::typedefDecl(); const QVector<UmlItem*>& children = parent()->children(); unsigned n = children.count(); unsigned index; // a typedef with the right definition already exist ? for (index = 0; index != n; index += 1) { if (children[index]->kind() == aClass) { UmlClass * cl = (UmlClass *) children[index]; if ((cl->stereotype() == "typedef") && (cl->cppDecl() == typedef_decl) && (cl->baseType().explicit_type == base)) { #ifdef ROUNDTRIP cl->set_usefull(); if (container_roundtrip) container_expected_order.append(cl); #endif return cl; } } } // must create typedef with a new name for (;;) { static unsigned nty; QString s("typedef%1"); s=s.arg(QString::number(++nty)); for (index = 0; index != n; index += 1) if (children[index]->name() == s) break; if (index == n) { UmlClass * cl = UmlClass::create(parent(), s.toLatin1().constData()); if (cl == 0) { #ifdef REVERSE UmlCom::message(""); CppCatWindow::trace(WrapperStr("<font face=helvetica><b>cannot create class <i>") + s + "</i> under <i>" + parent()->name() + "</b></font><br>"); throw 0; #else QMessageBox::critical(0, "Fatal Error", WrapperStr("<font face=helvetica><b>cannot create class <i>") + s + "</i> under <i>" + parent()->name() + "</b></font><br>"); QApplication::exit(1); #endif } UmlTypeSpec typespec; typespec.explicit_type = base; cl->set_Stereotype("typedef"); cl->set_BaseType(typespec); cl->set_CppDecl(typedef_decl); #ifdef REVERSE if (!libp) cl->need_artifact(Namespace::current()); # ifdef ROUNDTRIP if (container_roundtrip) container_expected_order.append(cl); # endif #endif return cl; } } }
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(); } }
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; }