Alien-SmokeQt

 view release on metacpan or  search on metacpan

generator/generatorvisitor.cpp  view on Meta::CPAN

        if (!n.isEmpty() && !parent.isEmpty()) n += "::";
        n += parent;
        
        foreach (const Enum& e, enums.values()) {
            if (e.parent())
                continue;
            
            if (e.nameSpace() == n) {
                foreach (const EnumMember& member, e.members()) {
                    if (member.name() == name) {
                        QString ret = n;
                        if (!ret.isEmpty())
                            ret += "::";
                        return ret + name;
                    }
                }
            }
        }
        
        if (!nspace.isEmpty())
            nspace.pop_back();
    } while (!nspace.isEmpty());

    QStack<Class*> parentStack = klass;
    while (!parentStack.isEmpty()) {
        const Class* clazz = parentStack.pop();
        foreach (const BasicTypeDeclaration* decl, clazz->children()) {
            const Enum *e = 0;
            if (!(e = dynamic_cast<const Enum*>(decl)))
                continue;
            foreach (const EnumMember& member, e->members()) {
                if (member.name() == name) {
                    return clazz->toString() + "::" + name;
                }
            }
        }
    }

    return QString();
}

#undef returnOnExistence

void GeneratorVisitor::visitAccessSpecifier(AccessSpecifierAST* node)
{
    static bool oldResolveTypedefs = ParserOptions::resolveTypedefs;

    if (!inClass) {
        DefaultVisitor::visitAccessSpecifier(node);
        return;
    }

    inSignals.top() = false;
    inSlots.top() = false;
    ParserOptions::resolveTypedefs = oldResolveTypedefs;

    const ListNode<std::size_t> *it = node->specs->toFront(), *end = it;
    do {
        if (it->element) {
            const Token& t = token(it->element);
            if (t.kind == Token_public)
                access.top() = Access_public;
            else if (t.kind == Token_protected)
                access.top() = Access_protected;
            else if (t.kind == Token_private)
                access.top() = Access_private;

            // signal/slot handling; don't resolve typedefs in signals and slots
            if (t.kind == Token_signals) {
                access.top() = Access_protected;
                inSignals.top() = true;
                ParserOptions::resolveTypedefs = false;
            } else if (t.kind == Token_slots) {
                inSlots.top() = true;
                ParserOptions::resolveTypedefs = false;
            }
        }
        it = it->next;
    } while (end != it);
    DefaultVisitor::visitAccessSpecifier(node);
}

void GeneratorVisitor::visitBaseSpecifier(BaseSpecifierAST* node)
{
    Class::BaseClassSpecifier baseClass;
    int _kind = token(node->access_specifier).kind;
    if (_kind == Token_public) {
        baseClass.access = Access_public;
    } else if (_kind == Token_protected) {
        baseClass.access = Access_protected;
    } else {
        baseClass.access = Access_private;
    }
    baseClass.isVirtual = (node->virt > 0);
    nc->run(node->name);
    BasicTypeDeclaration* base = resolveType(nc->qualifiedName().join("::"));
    if (!base)
        return;
    Class* bptr = dynamic_cast<Class*>(base);
    if (!bptr) {
        Typedef* tdef = dynamic_cast<Typedef*>(base);
        if (!tdef)
            return;
        bptr = tdef->resolve().getClass();
        if (!bptr)
            return;
    }
    baseClass.baseClass = bptr;
    klass.top()->appendBaseClass(baseClass);
}

void GeneratorVisitor::visitClassSpecifier(ClassSpecifierAST* node)
{
    if (klass.isEmpty())
        return;
    
    if (kind == Class::Kind_Class)
        access.push(Access_private);
    else
        access.push(Access_public);
    inSignals.push(false);
    inSlots.push(false);
    inClass++;
    q_properties.push(QList<QProperty>());
    
    klass.top()->setFileName(m_header);
    klass.top()->setIsForwardDecl(false);
    if (klass.count() > 1) {
        // get the element before the last element, which is the parent
        Class* parent = klass[klass.count() - 2];
        parent->appendChild(klass.top());
    }
    DefaultVisitor::visitClassSpecifier(node);
    q_properties.pop();
    access.pop();
    inSignals.pop();
    inSlots.pop();
    inClass--;
}

// defined later on
static bool operator==(const Method& rhs, const Method& lhs);

void GeneratorVisitor::visitDeclarator(DeclaratorAST* node)
{
    // TODO: get rid of this and add a proper typdef
    bool typeCreated = false;
    if (createType) {
        // run it again on the list of pointer operators to add them to the type
        tc->run(node);
        currentType = tc->type();
        currentTypeRef = Type::registerType(currentType);
        createType = false;
        typeCreated = true;
    }
    
    if (currentType.isFunctionPointer() && node->sub_declarator)
        nc->run(node->sub_declarator->id);
    else
        nc->run(node->id);
    const QString declName = nc->name();

    if (createTypedef) {
        if (!typeCreated)
            return;
        // we've just created the type that the typedef points to
        // so we just need to get the new name and store it
        Class* parent = klass.isEmpty() ? 0 : klass.top();
        Typedef tdef = Typedef(currentTypeRef, declName, nspace.join("::"), parent);
        tdef.setFileName(m_header);
        QString name = tdef.toString();
        if (!typedefs.contains(name)) {
            QHash<QString, Typedef>::iterator it = typedefs.insert(name, tdef);
            if (parent)
                parent->appendChild(&it.value());
        }
        createTypedef = false;
        return;
    }

generator/generatorvisitor.cpp  view on Meta::CPAN

                const ListNode<TypeIdAST*>* it = node->exception_spec->type_ids->toFront(), *end = it;
                do {
                    tc->run(it->element->type_specifier, it->element->declarator);
                    currentMethod.appendExceptionType(tc->type());
                    it = it->next;
                } while (it != end);
            }
        }

        klass.top()->appendMethod(currentMethod);
        return;
    }
    
    // global function
    if (node->parameter_declaration_clause && !inMethod && !inClass) {
        if (!declName.contains("::")) {
            Type* returnType = currentTypeRef;
            currentFunction = Function(declName, nspace.join("::"), returnType);
            currentFunction.setFileName(m_header);
            // build parameter list
            inMethod = true;
            visit(node->parameter_declaration_clause);
            inMethod = false;
            QString name = currentFunction.toString();
            if (!functions.contains(name)) {
                functions[name] = currentFunction;
            }
        }
        return;
    }
    
    // field
    if (!inMethod && !klass.isEmpty() && inClass) {
        Field field = Field(klass.top(), declName, currentTypeRef, access.top());
        if (isStatic) field.setFlag(Field::Static);
        klass.top()->appendField(field);
        return;
    } else if (!inMethod && !inClass) {
        // global variable
        if (!globals.contains(declName)) {
            GlobalVar var = GlobalVar(declName, nspace.join("::"), currentTypeRef);
            var.setFileName(m_header);
            globals[var.name()] = var;
        }
        return;
    }
}

void GeneratorVisitor::visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST* node)
{
    tc->run(node);
    createType = true;
    DefaultVisitor::visitElaboratedTypeSpecifier(node);
}

void GeneratorVisitor::visitEnumSpecifier(EnumSpecifierAST* node)
{
    nc->run(node->name);
    Class* parent = klass.isEmpty() ? 0 : klass.top();
    currentEnum = Enum(nc->name(), nspace.join("::"), parent);
    Access a = (access.isEmpty() ? Access_public : access.top());
    currentEnum.setAccess(a);
    currentEnum.setFileName(m_header);
    QHash<QString, Enum>::iterator it = enums.insert(currentEnum.toString(), currentEnum);
    currentEnumRef = &it.value();
    visitNodes(this, node->enumerators);
    if (parent)
        parent->appendChild(currentEnumRef);
}

void GeneratorVisitor::visitEnumerator(EnumeratorAST* node)
{
    currentEnumRef->appendMember(EnumMember(currentEnumRef, token(node->id).symbolString(), QString()));
//     DefaultVisitor::visitEnumerator(node);
}

void GeneratorVisitor::visitFunctionDefinition(FunctionDefinitionAST* node)
{
    visit(node->type_specifier);
    if (node->function_specifiers) {
        const ListNode<std::size_t> *it = node->function_specifiers->toFront(), *end = it;
        do {
            if (it->element && m_session->token_stream->kind(it->element) == Token_virtual) {
                // found virtual token
                isVirtual = true;
            } else if (it->element && m_session->token_stream->kind(it->element) == Token_explicit) {
                isExplicit = true;
            }
            it = it->next;
        } while (end != it);
    }
    if (node->storage_specifiers) {
        const ListNode<std::size_t> *it = node->storage_specifiers->toFront(), *end = it;
        do {
            if (it->element && m_session->token_stream->kind(it->element) == Token_static) {
                isStatic = true;
            } else if (it->element && m_session->token_stream->kind(it->element) == Token_friend) {
                // we're not interested in who's the friend of whom ;)
                return;
            }
            it = it->next;
        } while (end != it);
    }
    visit(node->init_declarator);
    isStatic = isVirtual = isExplicit = hasInitializer = false;
}

void GeneratorVisitor::visitInitializerClause(InitializerClauseAST *)
{
    // we don't care about initializers
    return;
}

void GeneratorVisitor::visitNamespace(NamespaceAST* node)
{
    usingTypes.push(QStringList());
    usingNamespaces.push(QStringList());

    QString name = token(node->namespace_name).symbolString();
    nspace.push_back(name);
    DefaultVisitor::visitNamespace(node);

generator/generatorvisitor.cpp  view on Meta::CPAN

            }

            QMap<int, QList<Type> > map = nc->templateArguments();
            for (QMap<int, QList<Type> >::const_iterator it = map.begin(); it != map.end(); it++) {
                QString str("< ");
                for (int i = 0; i < it.value().count(); i++) {
                    if (i > 0) str.append(',');
                    str.append(it.value()[i].toString());
                }
                str.append(" >");
                className[it.key()].append(str);
            }
            defaultValue.append(className.join("::"));
        } else if ((primary = ast_cast<PrimaryExpressionAST*>(node->expression))) {
            if (primary->name) {
                // don't build the default value twice
                expression = 0;
                // enum - try to resolve that
                nc->run(primary->name);
                
                QString name;
                // build the name of the containing class/namespace
                for (int i = 0; i < nc->qualifiedName().count() - 1; i++) {
                    if (i > 0) name.append("::");
                    name.append(nc->qualifiedName()[i]);
                }
                
                defaultValue = resolveEnumMember(name, nc->qualifiedName().last());
                if (defaultValue.isEmpty()) {
                    defaultValue = nc->qualifiedName().join("::");
                }
            }
        }
        
        if (expression) {
            for (int i = expression->start_token; i < expression->end_token; i++)
                defaultValue.append(token(i).symbolByteArray());
        }
    }
    if (inClass)
        currentMethod.appendParameter(Parameter(name, currentTypeRef, defaultValue));
    else
        currentFunction.appendParameter(Parameter(name, currentTypeRef, defaultValue));
}

void GeneratorVisitor::visitSimpleDeclaration(SimpleDeclarationAST* node)
{
    bool popKlass = false;
    int _kind = token(node->start_token).kind;
    if (_kind == Token_class) {
        kind = Class::Kind_Class;
    } else if (_kind == Token_struct) {
        kind = Class::Kind_Struct;
    }
    if (_kind == Token_class || _kind == Token_struct) {
        tc->run(node->type_specifier);
        if (tc->qualifiedName().isEmpty()) return;
        // for nested classes
        Class* parent = klass.isEmpty() ? 0 : klass.top();
        Class _class = Class(tc->qualifiedName().last(), nspace.join("::"), parent, kind);
        Access a = (access.isEmpty() ? Access_public : access.top());
        _class.setAccess(a);
        QString name = _class.toString();
        // This class has already been parsed.
        if (classes.contains(name) && !classes[name].isForwardDecl())
            return;
        QHash<QString, Class>::iterator item = classes.insert(name, _class);
        if (inTemplate) {
            item.value().setIsTemplate(true);
            return;
        }
        klass.push(&item.value());
        popKlass = true;
    }
    
    if (node->function_specifiers) {
        const ListNode<std::size_t> *it = node->function_specifiers->toFront(), *end = it;
        do {
            if (it->element && m_session->token_stream->kind(it->element) == Token_virtual) {
                // found virtual token
                isVirtual = true;
                break;
            }
            it = it->next;
        } while (end != it);
    }
    // look for initializers - if we find one, the method is pure virtual
    if (node->init_declarators) {
        const ListNode<InitDeclaratorAST*> *it = node->init_declarators->toFront(), *end = it;
        do {
            if (it->element && it->element->initializer) {
                hasInitializer = true;
            }
            if (it->element && it->element->declarator && it->element->declarator->parameter_declaration_clause) {
                if (popKlass) {
                    // This method return type has 'class' or 'struct' prepended to avoid a forward declaration.
                    // example: 'class KMultiTabBarTab *tab(...)'
                    QString oldClass = klass.top()->toString();
                    klass.top()->setParent(0);
                    klass.top()->setNameSpace(QString());
                    classes.insert(klass.top()->toString(), *klass.top());
                    classes.remove(oldClass);
                    klass.pop();
                    popKlass = false;
                }
            }
            it = it->next;
        } while (end != it);
    }
    if (node->storage_specifiers) {
        const ListNode<std::size_t> *it = node->storage_specifiers->toFront(), *end = it;
        do {
            if (it->element && m_session->token_stream->kind(it->element) == Token_static) {
                isStatic = true;
            } else if (it->element && m_session->token_stream->kind(it->element) == Token_friend) {
                // we're not interested in who's the friend of whom ;)
                if (popKlass)
                    klass.pop();
                isStatic = isVirtual = hasInitializer = false;
                return;
            }
            it = it->next;
        } while (end != it);
    }
    DefaultVisitor::visitSimpleDeclaration(node);
    if (popKlass)
        klass.pop();
    isStatic = isVirtual = hasInitializer = false;
}

void GeneratorVisitor::visitSimpleTypeSpecifier(SimpleTypeSpecifierAST* node)
{
    // first run on the type specifier to get the name of the type
    tc->run(node);
    createType = true;
    DefaultVisitor::visitSimpleTypeSpecifier(node);
}

void GeneratorVisitor::visitTemplateDeclaration(TemplateDeclarationAST* node)
{
    if (!node->declaration)
        return;
    int kind = token(node->declaration->start_token).kind;
    if (kind == Token_class || kind == Token_struct) {
        inTemplate = true;
        visit(node->declaration);
        inTemplate = false;
    }
    // skip template declarations
    return;
}

void GeneratorVisitor::visitTemplateArgument(TemplateArgumentAST* node)
{
    // skip template arguments - they're handled by TypeCompiler
    return;
}

void GeneratorVisitor::visitTypedef(TypedefAST* node)
{
    createTypedef = true;
    DefaultVisitor::visitTypedef(node);

    // TODO: probably has to be extended to cover structs and classes, too
    // makes something like 'typedef enum { Bar } Foo;' look like a proper enum.
    if (ast_cast<EnumSpecifierAST*>(node->type_specifier)) {
        nc->run(node->init_declarators->at(0)->element->declarator->id);
        currentEnumRef->setName(nc->name());
    }
}

// don't make this public - it's just a utility function for the next method and probably not what you would expect it to be
static bool operator==(const Method& rhs, const Method& lhs)
{
    // these have to be equal for methods to be the same
    bool ok = (rhs.name() == lhs.name() && rhs.isConst() == lhs.isConst() &&
               rhs.parameters().count() == lhs.parameters().count() && rhs.type() == lhs.type());
    if (!ok)
        return false;
    
    // now check the parameter types for equality
    for (int i = 0; i < rhs.parameters().count(); i++) {
        if (rhs.parameters()[i].type() != lhs.parameters()[i].type())
            return false;
    }
    
    return true;
}

void GeneratorVisitor::visitUsing(UsingAST* node)
{
    nc->run(node->name);
    if (inClass) {
        // if we encounter 'using' in a class, it means we should import methods from another class
        QStringList tmp = nc->qualifiedName();
        const QString methodName = tmp.takeLast();
        const QString className = tmp.join("::");
        const BasicTypeDeclaration* decl = resolveType(className);
        const Class* clazz = dynamic_cast<const Class*>(decl);
        if (!clazz) {
            const Typedef* tdef = dynamic_cast<const Typedef*>(decl);
            if (tdef) {
                clazz = tdef->resolve().getClass();
            }
        }
        if (!clazz)
            return;
        
        foreach (const Method& meth, clazz->methods()) {
            if (meth.name() != methodName)
                continue;
            
            // prevent importing of already overridden (pure) virtuals
            if (klass.top()->methods().contains(meth))
                continue;
            
            Method copy = meth;
            copy.setDeclaringType(klass.top());
            copy.setAccess(access.top());
            klass.top()->appendMethod(copy);
        }
    } else {
        usingTypes.top() << nc->qualifiedName().join("::");
    }
}

void GeneratorVisitor::visitUsingDirective(UsingDirectiveAST* node)
{
    nc->run(node->name);
    usingNamespaces.top() << nc->qualifiedName().join("::");
    DefaultVisitor::visitUsingDirective(node);
}



( run in 0.694 second using v1.01-cache-2.11-cpan-39bf76dae61 )