/** * 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 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; }