示例#1
0
/**
 * 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;
}
示例#2
0
/**
 * Figure out if the type is really an array or template of the given typeName.
 * Catenate possible template arguments/array dimensions to the end of the type name.
 * @param typeName   the type name
 * @return the type name with the additional information
 */
QString JavaImport::joinTypename(const QString& typeName)
{
    QString typeNameRet(typeName);
    if (m_srcIndex + 1 < m_source.size()) {
        if (m_source[m_srcIndex + 1] == "<" ||
            m_source[m_srcIndex + 1] == "[") {
            int start = ++m_srcIndex;
            if (! skipToClosing(m_source[start][0]))
                return typeNameRet;
            for (int i = start; i <= m_srcIndex; ++i) {
                typeNameRet += m_source[i];
            }
        }
    }
    // to handle multidimensional arrays, call recursively
    if ((m_srcIndex + 1 < m_source.size()) && (m_source[m_srcIndex + 1] == "[")) {
        typeNameRet = joinTypename( typeNameRet );
    }
    return typeNameRet;
}
示例#3
0
/**
 * 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;
}
示例#4
0
/**
 * 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;
}
示例#5
0
/**
 * 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;
}
示例#6
0
/**
 * 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;
}