/** * Parsing the statement 'enum'. * @return success status of parsing */ bool CSharpImport::parseStmtEnum() { const QString& name = advance(); log("enum " + name); UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Enum, name, m_scope[m_scopeIndex], m_comment); UMLEnum *enumType = static_cast<UMLEnum*>(ns); skipStmt("{"); while (m_srcIndex < m_source.count() - 1 && advance() != "}") { Import_Utils::addEnumLiteral(enumType, m_source[m_srcIndex]); QString next = advance(); if (next == "{" || next == "(") { if (! skipToClosing(next[0])) return false; next = advance(); } if (next != ",") { if (next == ";") { // @todo handle methods in enum // For now, we cheat (skip them) m_source[m_srcIndex] = '{'; if (! skipToClosing('{')) return false; } break; } } return true; }
/** * Parsing the statement 'namespace'. * @return success status of parsing */ bool CSharpImport::parseStmtNamespace() { QString m_currentNamespace = advance(); log("namespace " + m_currentNamespace); // move past { skipStmt("{"); return true; }
/** * Parsing the statement 'using'. * Keep track of imports so we can resolve classes we are dependent on. * @return success status of parsing */ bool CSharpImport::parseStmtUsing() { QString import = advance(); log("using " + import); if (import.contains('=')) { //this is an alias to represent the namespace name //:TODO: import = import + advance(); } m_imports.append(import); // move past ; skipStmt(); return true; }
/** * Check for, and skip over, all modifiers following a method. * Set the output arguments on encountering abstract and/or virtual. * @param isVirtual return value, set to true when "virtual" seen * @param isAbstract return value, set to true when "abstract" seen */ void PascalImport::checkModifiers(bool& isVirtual, bool& isAbstract) { const int srcLength = m_source.count(); while (m_srcIndex < srcLength - 1) { QString lookAhead = m_source[m_srcIndex + 1].toLower(); if (lookAhead != "virtual" && lookAhead != "abstract" && lookAhead != "override" && lookAhead != "register" && lookAhead != "cdecl" && lookAhead != "pascal" && lookAhead != "stdcall" && lookAhead != "safecall" && lookAhead != "saveregisters" && lookAhead != "popstack") break; if (lookAhead == "abstract") isAbstract = true; else if (lookAhead == "virtual") isVirtual = true; advance(); skipStmt(); } }
/** * Skip ahead to outermost closing brace. * @return body contents skipped */ QString PythonImport::skipBody() { /* During input preprocessing, changes in indentation were replaced by braces, and a semicolon was appended to each line ending. In order to return the body, we try to reconstruct the original Python syntax by reverting those changes. */ QString body; if (m_source[m_srcIndex] != QLatin1String("{")) skipStmt(QLatin1String("{")); bool firstTokenAfterNewline = true; int braceNesting = 0; QString token; while (!(token = advance()).isNull()) { if (token == QLatin1String("}")) { if (braceNesting <= 0) break; braceNesting--; body += QLatin1Char('\n'); firstTokenAfterNewline = true; } else if (token == QLatin1String("{")) { braceNesting++; body += QLatin1String(":\n"); firstTokenAfterNewline = true; } else if (token == QLatin1String(";")) { body += QLatin1Char('\n'); firstTokenAfterNewline = true; } else { if (firstTokenAfterNewline) { body += indentation(braceNesting); firstTokenAfterNewline = false; } else if (body.contains(QRegExp(QLatin1String("\\w$"))) && token.contains(QRegExp(QLatin1String("^\\w")))) { body += QLatin1Char(' '); } body += token; } } return body; }
/** * Implement abstract operation from NativeImportBase. */ bool AdaImport::parseStmt() { const int srcLength = m_source.count(); QString keyword = m_source[m_srcIndex]; UMLDoc *umldoc = UMLApp::app()->document(); //uDebug() << '"' << keyword << '"'; if (keyword == QLatin1String("with")) { if (m_inGenericFormalPart) { // mapping of generic formal subprograms or packages is not yet implemented return false; } while (++m_srcIndex < srcLength && m_source[m_srcIndex] != QLatin1String(";")) { QStringList components = m_source[m_srcIndex].toLower().split(QLatin1Char('.')); const QString& prefix = components.first(); if (prefix == QLatin1String("system") || prefix == QLatin1String("ada") || prefix == QLatin1String("gnat") || prefix == QLatin1String("interfaces") || prefix == QLatin1String("text_io") || prefix == QLatin1String("unchecked_conversion") || prefix == QLatin1String("unchecked_deallocation")) { if (advance() != QLatin1String(",")) break; continue; } parseStems(components); if (advance() != QLatin1String(",")) break; } return true; } if (keyword == QLatin1String("generic")) { m_inGenericFormalPart = true; return true; } if (keyword == QLatin1String("package")) { const QString& name = advance(); QStringList parentPkgs = name.toLower().split(QLatin1Char('.')); parentPkgs.pop_back(); // exclude the current package parseStems(parentPkgs); UMLObject *ns = NULL; if (advance() == QLatin1String("is")) { ns = Import_Utils::createUMLObject(UMLObject::ot_Package, name, currentScope(), m_comment); if (m_source[m_srcIndex + 1] == QLatin1String("new")) { m_srcIndex++; QString pkgName = advance(); UMLObject *gp = Import_Utils::createUMLObject(UMLObject::ot_Package, pkgName, currentScope()); gp->setStereotype(QLatin1String("generic")); // Add binding from instantiator to instantiatee UMLAssociation *assoc = new UMLAssociation(Uml::AssociationType::Dependency, ns, gp); assoc->setUMLPackage(umldoc->rootFolder(Uml::ModelType::Logical)); assoc->setStereotype(QLatin1String("bind")); // Work around missing display of stereotype in AssociationWidget: assoc->setName(assoc->stereotype(true)); umldoc->addAssociation(assoc); skipStmt(); } else { pushScope(static_cast<UMLPackage*>(ns)); } } else if (m_source[m_srcIndex] == QLatin1String("renames")) { m_renaming[name] = advance(); } else { uError() << "unexpected: " << m_source[m_srcIndex]; skipStmt(QLatin1String("is")); } if (m_inGenericFormalPart) { if (ns) ns->setStereotype(QLatin1String("generic")); m_inGenericFormalPart = false; } return true; } if (m_inGenericFormalPart) return false; // skip generic formal parameter (not yet implemented) if (keyword == QLatin1String("subtype")) { QString name = advance(); advance(); // "is" QString base = expand(advance()); base.remove(QLatin1String("Standard."), Qt::CaseInsensitive); UMLObject *type = umldoc->findUMLObject(base, UMLObject::ot_UMLObject, currentScope()); if (type == NULL) { type = Import_Utils::createUMLObject(UMLObject::ot_Datatype, base, currentScope()); } UMLObject *subtype = Import_Utils::createUMLObject(type->baseType(), name, currentScope(), m_comment); UMLAssociation *assoc = new UMLAssociation(Uml::AssociationType::Dependency, subtype, type); assoc->setUMLPackage(umldoc->rootFolder(Uml::ModelType::Logical)); assoc->setStereotype(QLatin1String("subtype")); // Work around missing display of stereotype in AssociationWidget: assoc->setName(assoc->stereotype(true)); umldoc->addAssociation(assoc); skipStmt(); return true; } if (keyword == QLatin1String("type")) { QString name = advance(); QString next = advance(); if (next == QLatin1String("(")) { uDebug() << name << ": discriminant handling is not yet implemented"; // @todo Find out how to map discriminated record to UML. // For now, we just create a pro forma empty record. Import_Utils::createUMLObject(UMLObject::ot_Class, name, currentScope(), m_comment, QLatin1String("record")); skipStmt(QLatin1String("end")); if ((next = advance()) == QLatin1String("case")) m_srcIndex += 2; // skip "case" ";" skipStmt(); return true; } if (next == QLatin1String(";")) { // forward declaration Import_Utils::createUMLObject(UMLObject::ot_Class, name, currentScope(), m_comment); return true; } if (next != QLatin1String("is")) { uError() << "expecting \"is\""; return false; } next = advance(); if (next == QLatin1String("(")) { // enum type UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Enum, name, currentScope(), m_comment); UMLEnum *enumType = static_cast<UMLEnum*>(ns); while ((next = advance()) != QLatin1String(")")) { Import_Utils::addEnumLiteral(enumType, next, m_comment); m_comment.clear(); if (advance() != QLatin1String(",")) break; } skipStmt(); return true; } bool isTaggedType = false; if (next == QLatin1String("abstract")) { m_isAbstract = true; next = advance(); } if (next == QLatin1String("tagged")) { isTaggedType = true; next = advance(); } if (next == QLatin1String("limited") || next == QLatin1String("task") || next == QLatin1String("protected") || next == QLatin1String("synchronized")) { next = advance(); // we can't (yet?) represent that } if (next == QLatin1String("private") || next == QLatin1String("interface") || next == QLatin1String("record") || (next == QLatin1String("null") && m_source[m_srcIndex+1] == QLatin1String("record"))) { UMLObject::ObjectType t = (next == QLatin1String("interface") ? UMLObject::ot_Interface : UMLObject::ot_Class); UMLObject *ns = Import_Utils::createUMLObject(t, name, currentScope(), m_comment); if (t == UMLObject::ot_Interface) { while ((next = advance()) == QLatin1String("and")) { UMLClassifier *klass = static_cast<UMLClassifier*>(ns); QString base = expand(advance()); UMLObject *p = Import_Utils::createUMLObject(UMLObject::ot_Interface, base, currentScope()); UMLClassifier *parent = static_cast<UMLClassifier*>(p); Import_Utils::createGeneralization(klass, parent); } } else { ns->setAbstract(m_isAbstract); } m_isAbstract = false; if (isTaggedType) { if (! m_classesDefinedInThisScope.contains(ns)) m_classesDefinedInThisScope.append(ns); } else { ns->setStereotype(QLatin1String("record")); } if (next == QLatin1String("record")) m_klass = static_cast<UMLClassifier*>(ns); else skipStmt(); return true; } if (next == QLatin1String("new")) { QString base = expand(advance()); QStringList baseInterfaces; while ((next = advance()) == QLatin1String("and")) { baseInterfaces.append(expand(advance())); } const bool isExtension = (next == QLatin1String("with")); UMLObject::ObjectType t; if (isExtension || m_isAbstract) { t = UMLObject::ot_Class; } else { base.remove(QLatin1String("Standard."), Qt::CaseInsensitive); UMLObject *known = umldoc->findUMLObject(base, UMLObject::ot_UMLObject, currentScope()); t = (known ? known->baseType() : UMLObject::ot_Datatype); } UMLObject *ns = Import_Utils::createUMLObject(t, base, NULL); UMLClassifier *parent = static_cast<UMLClassifier*>(ns); ns = Import_Utils::createUMLObject(t, name, currentScope(), m_comment); if (isExtension) { next = advance(); if (next == QLatin1String("null") || next == QLatin1String("record")) { UMLClassifier *klass = static_cast<UMLClassifier*>(ns); Import_Utils::createGeneralization(klass, parent); if (next == QLatin1String("record")) { // Set the m_klass for attributes. m_klass = klass; } if (baseInterfaces.count()) { t = UMLObject::ot_Interface; QStringList::Iterator end(baseInterfaces.end()); for (QStringList::Iterator bi(baseInterfaces.begin()); bi != end; ++bi) { ns = Import_Utils::createUMLObject(t, *bi, currentScope()); parent = static_cast<UMLClassifier*>(ns); Import_Utils::createGeneralization(klass, parent); } } } } skipStmt(); return true; } // Datatypes: TO BE DONE return false; } if (keyword == QLatin1String("private")) { m_currentAccess = Uml::Visibility::Private; return true; } if (keyword == QLatin1String("end")) { if (m_klass) { if (advance() != QLatin1String("record")) { uError() << "end: expecting \"record\" at " << m_source[m_srcIndex]; } m_klass = NULL; } else if (scopeIndex()) { if (advance() != QLatin1String(";")) { QString scopeName = currentScope()->fullyQualifiedName(); if (scopeName.toLower() != m_source[m_srcIndex].toLower()) uError() << "end: expecting " << scopeName << ", found " << m_source[m_srcIndex]; } popScope(); m_currentAccess = Uml::Visibility::Public; // @todo make a stack for this } else { uError() << "importAda: too many \"end\""; } skipStmt(); return true; } // subprogram if (keyword == QLatin1String("not")) keyword = advance(); if (keyword == QLatin1String("overriding")) keyword = advance(); if (keyword == QLatin1String("function") || keyword == QLatin1String("procedure")) { const QString& name = advance(); QString returnType; if (advance() != QLatin1String("(")) { // Unlike an Ada package, a UML package does not support // subprograms. // In order to map those, we would need to create a UML // class with stereotype <<utility>> for the Ada package. uDebug() << "ignoring parameterless " << keyword << " " << name; skipStmt(); return true; } UMLClassifier *klass = NULL; UMLOperation *op = NULL; const uint MAX_PARNAMES = 16; while (m_srcIndex < srcLength && m_source[m_srcIndex] != QLatin1String(")")) { QString parName[MAX_PARNAMES]; uint parNameCount = 0; do { if (parNameCount >= MAX_PARNAMES) { uError() << "MAX_PARNAMES is exceeded at " << name; break; } parName[parNameCount++] = advance(); } while (advance() == QLatin1String(",")); if (m_source[m_srcIndex] != QLatin1String(":")) { uError() << "importAda: expecting ':'"; skipStmt(); break; } const QString &direction = advance(); QString typeName; Uml::ParameterDirection::Enum dir = Uml::ParameterDirection::In; if (direction == QLatin1String("access")) { // Oops, we have to improvise here because there // is no such thing as "access" in UML. // So we use the next best thing, "inout". // Better ideas, anyone? dir = Uml::ParameterDirection::InOut; typeName = advance(); } else if (direction == QLatin1String("in")) { if (m_source[m_srcIndex + 1] == QLatin1String("out")) { dir = Uml::ParameterDirection::InOut; m_srcIndex++; } typeName = advance(); } else if (direction == QLatin1String("out")) { dir = Uml::ParameterDirection::Out; typeName = advance(); } else { typeName = direction; // In Ada, the default direction is "in" } typeName.remove(QLatin1String("Standard."), Qt::CaseInsensitive); typeName = expand(typeName); if (op == NULL) { // In Ada, the first parameter indicates the class. UMLObject *type = Import_Utils::createUMLObject(UMLObject::ot_Class, typeName, currentScope()); UMLObject::ObjectType t = type->baseType(); if ((t != UMLObject::ot_Interface && (t != UMLObject::ot_Class || type->stereotype() == QLatin1String("record"))) || !m_classesDefinedInThisScope.contains(type)) { // Not an instance bound method - we cannot represent it. skipStmt(QLatin1String(")")); break; } klass = static_cast<UMLClassifier*>(type); op = Import_Utils::makeOperation(klass, name); // The controlling parameter is suppressed. parNameCount--; if (parNameCount) { for (uint i = 0; i < parNameCount; ++i) { parName[i] = parName[i + 1]; } } } for (uint i = 0; i < parNameCount; ++i) { UMLAttribute *att = Import_Utils::addMethodParameter(op, typeName, parName[i]); att->setParmKind(dir); } if (advance() != QLatin1String(";")) break; } if (keyword == QLatin1String("function")) { if (advance() != QLatin1String("return")) { if (klass) uError() << "importAda: expecting \"return\" at function " << name; return false; } returnType = expand(advance()); returnType.remove(QLatin1String("Standard."), Qt::CaseInsensitive); } bool isAbstract = false; if (advance() == QLatin1String("is") && advance() == QLatin1String("abstract")) isAbstract = true; if (klass != NULL && op != NULL) Import_Utils::insertMethod(klass, op, m_currentAccess, returnType, false, isAbstract, false, false, m_comment); skipStmt(); return true; } if (keyword == QLatin1String("task") || keyword == QLatin1String("protected")) { // Can task and protected objects/types be mapped to UML? QString name = advance(); if (name == QLatin1String("type")) { name = advance(); } QString next = advance(); if (next == QLatin1String("(")) { skipStmt(QLatin1String(")")); // skip discriminant next = advance(); } if (next == QLatin1String("is")) skipStmt(QLatin1String("end")); skipStmt(); return true; } if (keyword == QLatin1String("for")) { // rep spec QString typeName = advance(); QString next = advance(); if (next == QLatin1String("'")) { advance(); // skip qualifier next = advance(); } if (next == QLatin1String("use")) { if (advance() == QLatin1String("record")) skipStmt(QLatin1String("end")); } else { uError() << "importAda: expecting \"use\" at rep spec of " << typeName; } skipStmt(); return true; } // At this point we're only interested in attribute declarations. if (m_klass == NULL || keyword == QLatin1String("null")) { skipStmt(); return true; } const QString& name = keyword; if (advance() != QLatin1String(":")) { uError() << "adaImport: expecting \":\" at " << name << " " << m_source[m_srcIndex]; skipStmt(); return true; } QString nextToken = advance(); if (nextToken == QLatin1String("aliased")) nextToken = advance(); QString typeName = expand(nextToken); QString initialValue; if (advance() == QLatin1String(":=")) { initialValue = advance(); QString token; while ((token = advance()) != QLatin1String(";")) { initialValue.append(QLatin1Char(' ') + token); } } UMLObject *o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name, typeName, m_comment); if (o) { UMLAttribute *attr = static_cast<UMLAttribute*>(o); attr->setInitialValue(initialValue); } skipStmt(); return true; }
/** * Implement abstract operation from NativeImportBase. * @return success status of operation */ bool JavaImport::parseStmt() { const int srcLength = m_source.count(); const QString& keyword = m_source[m_srcIndex]; //uDebug() << '"' << keyword << '"'; if (keyword == "package") { m_currentPackage = advance(); const QString& qualifiedName = m_currentPackage; const QStringList names = qualifiedName.split('.'); for (QStringList::ConstIterator it = names.begin(); it != names.end(); ++it) { QString name = (*it); log(keyword + ' ' + name); UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Package, name, m_scope[m_scopeIndex], m_comment); m_scope[++m_scopeIndex] = static_cast<UMLPackage*>(ns); } if (advance() != ";") { uError() << "importJava: unexpected: " << m_source[m_srcIndex]; skipStmt(); } return true; } if (keyword == "class" || keyword == "interface") { const QString& name = advance(); const UMLObject::ObjectType t = (keyword == "class" ? UMLObject::ot_Class : UMLObject::ot_Interface); log(keyword + ' ' + name); UMLObject *ns = Import_Utils::createUMLObject(t, name, m_scope[m_scopeIndex], m_comment); m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns); m_klass->setAbstract(m_isAbstract); m_klass->setStatic(m_isStatic); m_klass->setVisibility(m_currentAccess); // The UMLObject found by createUMLObject might originally have been created as a // placeholder with a type of class but if is really an interface, then we need to // change it. UMLObject::ObjectType ot = (keyword == "interface" ? UMLObject::ot_Interface : UMLObject::ot_Class); m_klass->setBaseType(ot); m_isAbstract = m_isStatic = false; // if no modifier is specified in an interface, then it means public if ( m_klass->isInterface() ) { m_defaultCurrentAccess = Uml::Visibility::Public; } if (advance() == ";") // forward declaration return true; if (m_source[m_srcIndex] == "<") { // template args - preliminary, rudimentary implementation // @todo implement all template arg syntax uint start = m_srcIndex; if (! skipToClosing('<')) { uError() << "importJava(" << name << "): template syntax error"; return false; } while (1) { const QString arg = m_source[++start]; if (! arg.contains( QRegExp("^[A-Za-z_]") )) { uDebug() << "importJava(" << name << "): cannot handle template syntax (" << arg << ")"; break; } /* UMLTemplate *tmpl = */ m_klass->addTemplate(arg); const QString next = m_source[++start]; if (next == ">") break; if (next != ",") { uDebug() << "importJava(" << name << "): cannot handle template syntax (" << next << ")"; break; } } advance(); // skip over ">" } if (m_source[m_srcIndex] == "extends") { const QString& baseName = advance(); // try to resolve the class we are extending, or if impossible // create a placeholder UMLObject *parent = resolveClass( baseName ); if ( parent ) { Import_Utils::createGeneralization(m_klass, static_cast<UMLClassifier*>(parent)); } else { uDebug() << "importJava parentClass " << baseName << " is not resolveable. Creating placeholder"; Import_Utils::createGeneralization(m_klass, baseName); } advance(); } if (m_source[m_srcIndex] == "implements") { while (m_srcIndex < srcLength - 1 && advance() != "{") { const QString& baseName = m_source[m_srcIndex]; // try to resolve the interface we are implementing, if this fails // create a placeholder UMLObject *interface = resolveClass( baseName ); if ( interface ) { Import_Utils::createGeneralization(m_klass, static_cast<UMLClassifier*>(interface)); } else { uDebug() << "importJava implementing interface "<< baseName <<" is not resolvable. Creating placeholder"; Import_Utils::createGeneralization(m_klass, baseName); } if (advance() != ",") break; } } if (m_source[m_srcIndex] != "{") { uError() << "importJava: ignoring excess chars at " << name << " (" << m_source[m_srcIndex] << ")"; skipStmt("{"); } return true; } if (keyword == "enum") { const QString& name = advance(); log(keyword + ' ' + name); UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Enum, name, m_scope[m_scopeIndex], m_comment); UMLEnum *enumType = static_cast<UMLEnum*>(ns); skipStmt("{"); while (m_srcIndex < srcLength - 1 && advance() != "}") { Import_Utils::addEnumLiteral(enumType, m_source[m_srcIndex]); QString next = advance(); if (next == "{" || next == "(") { if (! skipToClosing(next[0])) return false; next = advance(); } if (next != ",") { if (next == ";") { // @todo handle methods in enum // For now, we cheat (skip them) m_source[m_srcIndex] = '{'; if (! skipToClosing('{')) return false; } break; } } return true; } if (keyword == "static") { m_isStatic = true; return true; } // if we detected static previously and keyword is { then this is a static block if (m_isStatic && keyword == "{") { // reset static flag and jump to end of static block m_isStatic = false; return skipToClosing('{'); } if (keyword == "abstract") { m_isAbstract = true; return true; } if (keyword == "public") { m_currentAccess = Uml::Visibility::Public; return true; } if (keyword == "protected") { m_currentAccess = Uml::Visibility::Protected; return true; } if (keyword == "private") { m_currentAccess = Uml::Visibility::Private; return true; } if (keyword == "final" || keyword == "native" || keyword == "synchronized" || keyword == "transient" || keyword == "volatile") { //@todo anything to do here? return true; } if (keyword == "import") { // keep track of imports so we can resolve classes we are dependent on QString import = advance(); if ( import.endsWith('.') ) { //this most likely an import that ends with a * // import = import + advance(); } m_imports.append( import ); // move past ; skipStmt(); return true; } if (keyword == "@") { // annotation advance(); if (m_source[m_srcIndex + 1] == "(") { advance(); skipToClosing('('); } return true; } if (keyword == "}") { if (m_scopeIndex) m_klass = dynamic_cast<UMLClassifier*>(m_scope[--m_scopeIndex]); else uError() << "importJava: too many }"; return true; } // At this point, we expect `keyword' to be a type name // (of a member of class or interface, or return type // of an operation.) Up next is the name of the attribute // or operation. if (! keyword.contains( QRegExp("^\\w") )) { uError() << "importJava: ignoring " << keyword << " at " << m_srcIndex << ", " << m_source.count() << " in " << m_klass->name(); return false; } QString typeName = m_source[m_srcIndex]; typeName = joinTypename(typeName); // At this point we need a class. if (m_klass == NULL) { uError() << "importJava: no class set for " << typeName; return false; } QString name = advance(); QString nextToken; if (typeName == m_klass->name() && name == "(") { // Constructor. nextToken = name; name = typeName; typeName.clear(); } else { nextToken = advance(); } if (name.contains( QRegExp("\\W") )) { uError() << "importJava: expecting name in " << name; return false; } if (nextToken == "(") { // operation UMLOperation *op = Import_Utils::makeOperation(m_klass, name); m_srcIndex++; while (m_srcIndex < srcLength && m_source[m_srcIndex] != ")") { QString typeName = m_source[m_srcIndex]; if ( typeName == "final" || typeName.startsWith( "//") ) { // ignore the "final" keyword and any comments in method args typeName = advance(); } typeName = joinTypename(typeName); QString parName = advance(); // the Class might not be resolved yet so resolve it if necessary UMLObject *obj = resolveClass(typeName); if (obj) { // by prepending the package, unwanted placeholder types will not get created typeName = obj->fullyQualifiedName("."); } /* UMLAttribute *att = */ Import_Utils::addMethodParameter(op, typeName, parName); if (advance() != ",") break; m_srcIndex++; } // before adding the method, try resolving the return type UMLObject *obj = resolveClass(typeName); if (obj) { // using the fully qualified name means that a placeholder type will not be created. typeName = obj->fullyQualifiedName("."); } Import_Utils::insertMethod(m_klass, op, m_currentAccess, typeName, m_isStatic, m_isAbstract, false /*isFriend*/, false /*isConstructor*/, m_comment); m_isAbstract = m_isStatic = false; // reset the default visibility m_currentAccess = m_defaultCurrentAccess; // At this point we do not know whether the method has a body or not. do { nextToken = advance(); } while (nextToken != "{" && nextToken != ";"); if (nextToken == ";") { // No body (interface or abstract) return true; } else { return skipToClosing('{'); } } // At this point we know it's some kind of attribute declaration. while (1) { while (nextToken != "," && nextToken != ";") { if (nextToken == "=") { if ((nextToken = advance()) == "new") { advance(); if ((nextToken = advance()) == "(") { skipToClosing('('); if ((nextToken = advance()) == "{") { skipToClosing('{'); } else { skipStmt(); break; } } else { skipStmt(); break; } } else { skipStmt(); break; } } else { name += nextToken; // add possible array dimensions to `name' } nextToken = advance(); if (nextToken.isEmpty()) { break; } } // try to resolve the class type, or create a placeholder if that fails UMLObject *type = resolveClass( typeName ); UMLObject *o; if (type) { o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name, static_cast<UMLClassifier*>(type), m_comment, m_isStatic); } else { o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name, typeName, m_comment, m_isStatic); } // UMLAttribute *attr = static_cast<UMLAttribute*>(o); if (nextToken != ",") { // reset the modifiers m_isStatic = m_isAbstract = false; break; } name = advance(); nextToken = advance(); } // reset visibility to default m_currentAccess = m_defaultCurrentAccess; if (m_srcIndex < m_source.count()) { if (m_source[m_srcIndex] != ";") { uError() << "importJava: ignoring trailing items at " << name; skipStmt(); } } else { uError() << "index out of range: ignoring statement " << name; skipStmt(); } return true; }
/** * Implement abstract operation from NativeImportBase. * @return success status of operation */ bool PythonImport::parseStmt() { const int srcLength = m_source.count(); const QString& keyword = m_source[m_srcIndex]; if (keyword == "class") { const QString& name = advance(); UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Class, name, m_scope[m_scopeIndex], m_comment); m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns); m_comment.clear(); if (advance() == "(") { while (m_srcIndex < srcLength - 1 && advance() != ")") { const QString& baseName = m_source[m_srcIndex]; Import_Utils::createGeneralization(m_klass, baseName); if (advance() != ",") break; } } if (m_source[m_srcIndex] != "{") { skipStmt("{"); } log("class " + name); return true; } if (keyword == "def") { if (m_klass == NULL) { // skip functions outside of a class skipBody(); return true; } const QString& name = advance(); // operation UMLOperation *op = Import_Utils::makeOperation(m_klass, name); if (advance() != "(") { uError() << "importPython def " << name << ": expecting \"(\""; skipBody(); return true; } while (m_srcIndex < srcLength && advance() != ")") { const QString& parName = m_source[m_srcIndex]; /*UMLAttribute *att =*/ Import_Utils::addMethodParameter(op, "string", parName); if (advance() != ",") break; } Import_Utils::insertMethod(m_klass, op, Uml::Visibility::Public, "string", false /*isStatic*/, false /*isAbstract*/, false /*isFriend*/, false /*isConstructor*/, m_comment); op->setSourceCode(skipBody()); log("def " + name); return true; } if (keyword == "}") { if (m_scopeIndex) m_klass = dynamic_cast<UMLClassifier*>(m_scope[--m_scopeIndex]); else uError() << "parsing: too many }"; return true; } return false; // @todo parsing of attributes }
/** * Implement abstract operation from NativeImportBase. * @return success status of operation */ bool PythonImport::parseStmt() { const int srcLength = m_source.count(); const QString& keyword = m_source[m_srcIndex]; if (keyword == QLatin1String("class")) { const QString& name = advance(); UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Class, name, currentScope(), m_comment); pushScope(m_klass = static_cast<UMLClassifier*>(ns)); m_comment.clear(); if (advance() == QLatin1String("(")) { while (m_srcIndex < srcLength - 1 && advance() != QLatin1String(")")) { const QString& baseName = m_source[m_srcIndex]; Import_Utils::createGeneralization(m_klass, baseName); if (advance() != QLatin1String(",")) break; } } if (m_source[m_srcIndex] != QLatin1String("{")) { skipStmt(QLatin1String("{")); } log(QLatin1String("class ") + name); return true; } if (keyword == QLatin1String("@")) { const QString& annotation = m_source[++m_srcIndex]; uDebug() << "annotation:" << annotation; if (annotation == QLatin1String("staticmethod")) m_isStatic = true; return true; } if (keyword == QLatin1String("def")) { if (m_klass == NULL) { // skip functions outside of a class skipBody(); return true; } if (!m_klass->hasDoc() && !m_comment.isEmpty()) { m_klass->setDoc(m_comment); m_comment = QString(); } const QString& name = advance(); // operation UMLOperation *op = Import_Utils::makeOperation(m_klass, name); if (advance() != QLatin1String("(")) { uError() << "importPython def " << name << ": expecting \"(\""; skipBody(); return true; } bool firstParam = true; while (m_srcIndex < srcLength && advance() != QLatin1String(")")) { const QString& parName = m_source[m_srcIndex]; if (firstParam) { if (parName.compare(QLatin1String("self"), Qt::CaseInsensitive) != 0) { m_isStatic = true; Import_Utils::addMethodParameter(op, QLatin1String("string"), parName); } firstParam = false; } else { /*UMLAttribute *att =*/ Import_Utils::addMethodParameter(op, QLatin1String("string"), parName); } if (advance() != QLatin1String(",")) break; } Import_Utils::insertMethod(m_klass, op, Uml::Visibility::Public, QLatin1String("string"), m_isStatic, false /*isAbstract*/, false /*isFriend*/, false /*isConstructor*/, m_comment); m_isStatic = false; op->setSourceCode(skipBody()); if (!op->hasDoc() && !m_comment.isEmpty()) { op->setDoc(m_comment); m_comment = QString(); } log(QLatin1String("def ") + name); return true; } if (keyword == QLatin1String("}")) { if (scopeIndex()) { m_klass = dynamic_cast<UMLClassifier*>(popScope()); } else uError() << "parsing: too many }"; return true; } return false; // @todo parsing of attributes }
/** * Implement abstract operation from NativeImportBase. * @return success status of operation */ bool PascalImport::parseStmt() { const int srcLength = m_source.count(); QString keyword = m_source[m_srcIndex].toLower(); //uDebug() << '"' << keyword << '"'; if (keyword == "uses") { while (m_srcIndex < srcLength - 1) { QString unit = advance(); const QString& prefix = unit.toLower(); if (prefix == "sysutils" || prefix == "types" || prefix == "classes" || prefix == "graphics" || prefix == "controls" || prefix == "strings" || prefix == "forms" || prefix == "windows" || prefix == "messages" || prefix == "variants" || prefix == "stdctrls" || prefix == "extctrls" || prefix == "activex" || prefix == "comobj" || prefix == "registry" || prefix == "classes" || prefix == "dialogs") { if (advance() != ",") break; continue; } QString filename = unit + ".pas"; if (! m_parsedFiles.contains(unit)) { // Save current m_source and m_srcIndex. QStringList source(m_source); uint srcIndex = m_srcIndex; m_source.clear(); parseFile(filename); // Restore m_source and m_srcIndex. m_source = source; m_srcIndex = srcIndex; // Also reset m_currentAccess. // CHECK: need to reset more stuff? m_currentAccess = Uml::Visibility::Public; } if (advance() != ",") break; } return true; } if (keyword == "unit") { const QString& name = advance(); UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Package, name, m_scope[m_scopeIndex], m_comment); m_scope[++m_scopeIndex] = static_cast<UMLPackage*>(ns); skipStmt(); return true; } if (keyword == "interface") { m_inInterface = true; return true; } if (keyword == "initialization" || keyword == "implementation") { m_inInterface = false; return true; } if (! m_inInterface) { // @todo parseStmt() should support a notion for "quit parsing, close file immediately" return false; } if (keyword == "label") { m_section = sect_LABEL; return true; } if (keyword == "const") { m_section = sect_CONST; return true; } if (keyword == "resourcestring") { m_section = sect_RESOURCESTRING; return true; } if (keyword == "type") { m_section = sect_TYPE; return true; } if (keyword == "var") { m_section = sect_VAR; return true; } if (keyword == "threadvar") { m_section = sect_THREADVAR; return true; } if (keyword == "automated" || keyword == "published" // no concept in UML || keyword == "public") { m_currentAccess = Uml::Visibility::Public; return true; } if (keyword == "protected") { m_currentAccess = Uml::Visibility::Protected; return true; } if (keyword == "private") { m_currentAccess = Uml::Visibility::Private; return true; } if (keyword == "packed") { return true; // TBC: perhaps this could be stored in a TaggedValue } if (keyword == "[") { skipStmt("]"); return true; } if (keyword == "end") { if (m_klass) { m_klass = NULL; } else if (m_scopeIndex) { m_scopeIndex--; m_currentAccess = Uml::Visibility::Public; } else { uError() << "importPascal: too many \"end\""; } skipStmt(); return true; } if (keyword == "function" || keyword == "procedure" || keyword == "constructor" || keyword == "destructor") { if (m_klass == NULL) { // Unlike a Pascal unit, a UML package does not support subprograms. // In order to map those, we would need to create a UML class with // stereotype <<utility>> for the unit, http://bugs.kde.org/89167 bool dummyVirtual = false; bool dummyAbstract = false; checkModifiers(dummyVirtual, dummyAbstract); return true; } const QString& name = advance(); UMLOperation *op = Import_Utils::makeOperation(m_klass, name); if (m_source[m_srcIndex + 1] == "(") { advance(); const uint MAX_PARNAMES = 16; while (m_srcIndex < srcLength && m_source[m_srcIndex] != ")") { QString nextToken = m_source[m_srcIndex + 1].toLower(); Uml::Parameter_Direction dir = Uml::pd_In; if (nextToken == "var") { dir = Uml::pd_InOut; advance(); } else if (nextToken == "const") { advance(); } else if (nextToken == "out") { dir = Uml::pd_Out; advance(); } QString parName[MAX_PARNAMES]; uint parNameCount = 0; do { if (parNameCount >= MAX_PARNAMES) { uError() << "MAX_PARNAMES is exceeded at " << name; break; } parName[parNameCount++] = advance(); } while (advance() == ","); if (m_source[m_srcIndex] != ":") { uError() << "importPascal: expecting ':' at " << m_source[m_srcIndex]; skipStmt(); break; } nextToken = advance(); if (nextToken.toLower() == "array") { nextToken = advance().toLower(); if (nextToken != "of") { uError() << "importPascal(" << name << "): expecting 'array OF' at " << nextToken; skipStmt(); return false; } nextToken = advance(); } for (uint i = 0; i < parNameCount; ++i) { UMLAttribute *att = Import_Utils::addMethodParameter(op, nextToken, parName[i]); att->setParmKind(dir); } if (advance() != ";") break; } } QString returnType; if (keyword == "function") { if (advance() != ":") { uError() << "importPascal: expecting \":\" at function " << name; return false; } returnType = advance(); } else if (keyword == "constructor" || keyword == "destructor") { op->setStereotype(keyword); } skipStmt(); bool isVirtual = false; bool isAbstract = false; checkModifiers(isVirtual, isAbstract); Import_Utils::insertMethod(m_klass, op, m_currentAccess, returnType, !isVirtual, isAbstract, false, false, m_comment); return true; } if (m_section != sect_TYPE) { skipStmt(); return true; } if (m_klass == NULL) { const QString& name = m_source[m_srcIndex]; QString nextToken = advance(); if (nextToken != "=") { uDebug() << name << ": expecting '=' at " << nextToken; return false; } keyword = advance().toLower(); if (keyword == "(") { // enum type UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Enum, name, m_scope[m_scopeIndex], m_comment); UMLEnum *enumType = static_cast<UMLEnum*>(ns); while (++m_srcIndex < srcLength && m_source[m_srcIndex] != ")") { Import_Utils::addEnumLiteral(enumType, m_source[m_srcIndex]); if (advance() != ",") break; } skipStmt(); return true; } if (keyword == "set") { // @todo implement Pascal set types skipStmt(); return true; } if (keyword == "array") { // @todo implement Pascal array types skipStmt(); return true; } if (keyword == "file") { // @todo implement Pascal file types skipStmt(); return true; } if (keyword == "^") { // @todo implement Pascal pointer types skipStmt(); return true; } if (keyword == "class" || keyword == "interface") { Uml::Object_Type t = (keyword == "class" ? Uml::ot_Class : Uml::ot_Interface); UMLObject *ns = Import_Utils::createUMLObject(t, name, m_scope[m_scopeIndex], m_comment); UMLClassifier *klass = static_cast<UMLClassifier*>(ns); m_comment.clear(); QString lookAhead = m_source[m_srcIndex + 1]; if (lookAhead == "(") { advance(); do { QString base = advance(); UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class, base, NULL); UMLClassifier *parent = static_cast<UMLClassifier*>(ns); m_comment.clear(); Import_Utils::createGeneralization(klass, parent); } while (advance() == ","); if (m_source[m_srcIndex] != ")") { uError() << "PascalImport: expecting \")\" at " << m_source[m_srcIndex]; return false; } lookAhead = m_source[m_srcIndex + 1]; } if (lookAhead == ";") { skipStmt(); return true; } if (lookAhead == "of") { // @todo implement class-reference type return false; } m_klass = klass; m_currentAccess = Uml::Visibility::Public; return true; } if (keyword == "record") { UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class, name, m_scope[m_scopeIndex], m_comment); ns->setStereotype("record"); m_klass = static_cast<UMLClassifier*>(ns); return true; } if (keyword == "function" || keyword == "procedure") { /*UMLObject *ns =*/ Import_Utils::createUMLObject(Uml::ot_Datatype, name, m_scope[m_scopeIndex], m_comment); if (m_source[m_srcIndex + 1] == "(") skipToClosing('('); skipStmt(); return true; } // Datatypes: TO BE DONE return false; } // At this point we need a class because we're expecting its member attributes. if (m_klass == NULL) { uDebug() << "importPascal: skipping " << m_source[m_srcIndex]; skipStmt(); return true; } QString name, stereotype; if (keyword == "property") { stereotype = keyword; name = advance(); } else { name = m_source[m_srcIndex]; } if (advance() != ":") { uError() << "PascalImport: expecting \":\" at " << name << " " << m_source[m_srcIndex]; skipStmt(); return true; } QString typeName = advance(); QString initialValue; if (advance() == "=") { initialValue = advance(); QString token; while ((token = advance()) != ";") { initialValue.append(' ' + token); } } UMLObject *o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name, typeName, m_comment); UMLAttribute *attr = static_cast<UMLAttribute*>(o); attr->setStereotype(stereotype); attr->setInitialValue(initialValue); skipStmt(); return true; }
/** * Implement abstract operation from NativeImportBase. * @return success status of operation */ bool CSharpImport::parseStmt() { const int srcLength = m_source.count(); const QString& keyword = m_source[m_srcIndex]; //uDebug() << '"' << keyword << '"'; if (keyword == "using") { return parseStmtUsing(); } if (keyword == "namespace") { return parseStmtNamespace(); } // if (keyword == "package") { // m_currentPackage = advance(); // const QString& qualifiedName = m_currentPackage; // const QStringList names = qualifiedName.split('.'); // for (QStringList::ConstIterator it = names.begin(); it != names.end(); ++it) { // QString name = (*it); // log(keyword + ' ' + name); // UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Package, // name, m_scope[m_scopeIndex], m_comment); // m_scope[++m_scopeIndex] = static_cast<UMLPackage*>(ns); // } // if (advance() != ";") { // uError() << "unexpected: " << m_source[m_srcIndex]; // skipStmt(); // } // return true; // } if (keyword == "class" || keyword == "interface") { return parseStmtClass(keyword); } if (keyword == "enum") { return parseStmtEnum(); } if (keyword == "static") { m_isStatic = true; return true; } // if we detected static previously and keyword is { then this is a static block if (m_isStatic && keyword == "{") { // reset static flag and jump to end of static block m_isStatic = false; return skipToClosing('{'); } if (keyword == "abstract") { m_isAbstract = true; return true; } if (keyword == "public") { m_currentAccess = Uml::Visibility::Public; return true; } if (keyword == "protected") { m_currentAccess = Uml::Visibility::Protected; return true; } if (keyword == "private") { m_currentAccess = Uml::Visibility::Private; return true; } if ((keyword == "override") || (keyword == "virtual") || (keyword == "sealed")) { //:TODO: anything to do here? return true; } if (keyword == "#") { // preprocessor directives QString ppdKeyword = advance(); uDebug() << "found preprocessor directive " << ppdKeyword; //:TODO: anything to do here? return true; } // if (keyword == "@") { // annotation // advance(); // if (m_source[m_srcIndex + 1] == "(") { // advance(); // skipToClosing('('); // } // return true; // } if (keyword == "[") { // ... advance(); skipToClosing('['); return true; } if (keyword == "}") { if (m_scopeIndex) m_klass = dynamic_cast<UMLClassifier*>(m_scope[--m_scopeIndex]); else uError() << "too many }"; return true; } // At this point, we expect `keyword' to be a type name // (of a member of class or interface, or return type // of an operation.) Up next is the name of the attribute // or operation. if (! keyword.contains(QRegExp("^\\w"))) { uError() << "ignoring " << keyword << " at " << m_srcIndex << ", " << m_source.count() << " in " << m_klass; //:TODO: ->name(); return false; } QString typeName = m_source[m_srcIndex]; typeName = joinTypename(typeName); // At this point we need a class. if (m_klass == NULL) { uError() << "no class set for " << typeName; return false; } QString name = advance(); QString nextToken; if (typeName == m_klass->name() && name == "(") { // Constructor. nextToken = name; name = typeName; typeName.clear(); } else { nextToken = advance(); } if (name.contains(QRegExp("\\W"))) { uError() << "expecting name in " << name; return false; } if (nextToken == "(") { // operation UMLOperation *op = Import_Utils::makeOperation(m_klass, name); m_srcIndex++; while (m_srcIndex < srcLength && m_source[m_srcIndex] != ")") { QString typeName = m_source[m_srcIndex]; if (typeName == "final" || typeName.startsWith("//")) { // ignore the "final" keyword and any comments in method args typeName = advance(); } typeName = joinTypename(typeName); QString parName = advance(); // the Class might not be resolved yet so resolve it if necessary UMLObject *obj = resolveClass(typeName); if (obj) { // by prepending the package, unwanted placeholder types will not get created typeName = obj->fullyQualifiedName("."); } /* UMLAttribute *att = */ Import_Utils::addMethodParameter(op, typeName, parName); if (advance() != ",") break; m_srcIndex++; } // before adding the method, try resolving the return type UMLObject *obj = resolveClass(typeName); if (obj) { // using the fully qualified name means that a placeholder type will not be created. typeName = obj->fullyQualifiedName("."); } Import_Utils::insertMethod(m_klass, op, m_currentAccess, typeName, m_isStatic, m_isAbstract, false /*isFriend*/, false /*isConstructor*/, m_comment); m_isAbstract = m_isStatic = false; // reset the default visibility m_currentAccess = m_defaultCurrentAccess; // At this point we do not know whether the method has a body or not. do { nextToken = advance(); } while (nextToken != "{" && nextToken != ";"); if (nextToken == ";") { // No body (interface or abstract) return true; } else { return skipToClosing('{'); } } // At this point we know it's some kind of attribute declaration. while(1) { while (nextToken != "," && nextToken != ";") { if (nextToken == "=") { if ((nextToken = advance()) == "new") { advance(); if ((nextToken = advance()) == "(") { skipToClosing('('); if ((nextToken = advance()) == "{") { skipToClosing('{'); } else { skipStmt(); break; } } else { skipStmt(); break; } } else { skipStmt(); break; } } else { name += nextToken; // add possible array dimensions to `name' } nextToken = advance(); if (nextToken.isEmpty()) { break; } } // try to resolve the class type, or create a placeholder if that fails UMLObject *type = resolveClass(typeName); UMLObject *o; if (type) { o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name, static_cast<UMLClassifier*>(type), m_comment, m_isStatic); } else { o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name, typeName, m_comment, m_isStatic); } // UMLAttribute *attr = static_cast<UMLAttribute*>(o); if (nextToken != ",") { // reset the modifiers m_isStatic = m_isAbstract = false; break; } name = advance(); nextToken = advance(); } // reset visibility to default m_currentAccess = m_defaultCurrentAccess; if (m_srcIndex < m_source.count()) { if (m_source[m_srcIndex] != ";") { uError() << "ignoring trailing items at " << name; skipStmt(); } } else { uError() << "index out of range: ignoring statement " << name; skipStmt(); } return true; }
/** * Parsing the statement 'class' or 'interface'. * @return success status of parsing */ bool CSharpImport::parseStmtClass(const QString& keyword) { const QString& name = advance(); const UMLObject::ObjectType t = (keyword == "class" ? UMLObject::ot_Class : UMLObject::ot_Interface); log(keyword + ' ' + name); UMLObject *ns = Import_Utils::createUMLObject(t, name, m_scope[m_scopeIndex], m_comment); m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns); m_klass->setAbstract(m_isAbstract); m_klass->setStatic(m_isStatic); m_klass->setVisibility(m_currentAccess); // The UMLObject found by createUMLObject might originally have been created as a // placeholder with a type of class but if is really an interface, then we need to // change it. UMLObject::ObjectType ot = (keyword == "interface" ? UMLObject::ot_Interface : UMLObject::ot_Class); m_klass->setBaseType(ot); m_isAbstract = m_isStatic = false; // if no modifier is specified in an interface, then it means public if (m_klass->isInterface()) { m_defaultCurrentAccess = Uml::Visibility::Public; } if (advance() == ";") // forward declaration return true; if (m_source[m_srcIndex] == "<") { // template args - preliminary, rudimentary implementation // @todo implement all template arg syntax uint start = m_srcIndex; if (! skipToClosing('<')) { uError() << "import C# (" << name << "): template syntax error"; return false; } while(1) { const QString arg = m_source[++start]; if (! arg.contains(QRegExp("^[A-Za-z_]"))) { uDebug() << "import C# (" << name << "): cannot handle template syntax (" << arg << ")"; break; } /* UMLTemplate *tmpl = */ m_klass->addTemplate(arg); const QString next = m_source[++start]; if (next == ">") break; if (next != ",") { uDebug() << "import C# (" << name << "): cannot handle template syntax (" << next << ")"; break; } } advance(); // skip over ">" } if (m_source[m_srcIndex] == ":") { // derivation while (m_srcIndex < m_source.count() - 1 && advance() != "{") { const QString& baseName = m_source[m_srcIndex]; // try to resolve the interface we are implementing, if this fails // create a placeholder UMLObject *interface = resolveClass(baseName); if (interface) { Import_Utils::createGeneralization(m_klass, static_cast<UMLClassifier*>(interface)); } else { uDebug() << "implementing interface " << baseName << " is not resolvable. Creating placeholder"; Import_Utils::createGeneralization(m_klass, baseName); } if (advance() != ",") break; } } if (m_source[m_srcIndex] != "{") { uError() << "ignoring excess chars at " << name << " (" << m_source[m_srcIndex] << ")"; skipStmt("{"); } return true; }
/** * Implement abstract operation from NativeImportBase. * @return success status of operation */ bool PythonImport::parseStmt() { const int srcLength = m_source.count(); QString keyword = m_source[m_srcIndex]; if (keyword == QLatin1String("class")) { const QString& name = advance(); UMLObject *ns = Import_Utils::createUMLObject(UMLObject::ot_Class, name, currentScope(), m_comment); pushScope(m_klass = ns->asUMLClassifier()); m_comment.clear(); if (advance() == QLatin1String("(")) { while (m_srcIndex < srcLength - 1 && advance() != QLatin1String(")")) { const QString& baseName = m_source[m_srcIndex]; Import_Utils::createGeneralization(m_klass, baseName); if (advance() != QLatin1String(",")) break; } } if (m_source[m_srcIndex] != QLatin1String("{")) { skipStmt(QLatin1String("{")); } log(QLatin1String("class ") + name); return true; } if (keyword == QLatin1String("@")) { const QString& annotation = m_source[++m_srcIndex]; uDebug() << "annotation:" << annotation; if (annotation == QLatin1String("staticmethod")) m_isStatic = true; return true; } if (keyword == QLatin1String("def")) { if (m_klass == 0) { // skip functions outside of a class skipBody(); return true; } if (!m_klass->hasDoc() && !m_comment.isEmpty()) { m_klass->setDoc(m_comment); m_comment = QString(); } const QString& name = advance(); // operation UMLOperation *op = Import_Utils::makeOperation(m_klass, name); if (advance() != QLatin1String("(")) { uError() << "importPython def " << name << ": expecting \"(\""; skipBody(); return true; } bool firstParam = true; while (m_srcIndex < srcLength && advance() != QLatin1String(")")) { const QString& parName = m_source[m_srcIndex]; if (firstParam) { if (parName.compare(QLatin1String("self"), Qt::CaseInsensitive) != 0) { m_isStatic = true; Import_Utils::addMethodParameter(op, QLatin1String("string"), parName); } firstParam = false; } else { /*UMLAttribute *att =*/ Import_Utils::addMethodParameter(op, QLatin1String("string"), parName); } if (advance() != QLatin1String(",")) break; } Import_Utils::insertMethod(m_klass, op, Uml::Visibility::Public, QLatin1String("string"), m_isStatic, false /*isAbstract*/, false /*isFriend*/, false /*isConstructor*/, m_comment); m_isStatic = false; int srcIndex = m_srcIndex; op->setSourceCode(skipBody()); if (!op->hasDoc() && !m_comment.isEmpty()) { op->setDoc(m_comment); m_comment = QString(); } // parse instance variables from __init__ method if (name == QLatin1String("__init__")) { int indexSave = m_srcIndex; m_srcIndex = srcIndex; advance(); keyword = advance(); while (m_srcIndex < indexSave) { if (lookAhead() == QLatin1String("=")) { parseAssignmentStmt(keyword); // skip ; inserted by lexer if (lookAhead() == QLatin1String(";")) { advance(); keyword = advance(); } } else { skipStmt(QLatin1String(";")); keyword = advance(); } } m_srcIndex = indexSave; } log(QLatin1String("def ") + name); return true; } // parse class variables if (m_klass && lookAhead() == QLatin1String("=")) { bool result = parseAssignmentStmt(keyword); log(QLatin1String("class attribute ") + keyword); return result; } if (keyword == QLatin1String("}")) { if (scopeIndex()) { m_klass = popScope()->asUMLClassifier(); } else uError() << "parsing: too many }"; return true; } return false; // @todo parsing of attributes }