📄 moc.cpp
字号:
while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED) || test(STAR) || test(AND)) { type.name += ' '; type.name += lexem(); if (lookup(0) == AND) type.referenceType = Type::Reference; else if (lookup(0) == STAR) type.referenceType = Type::Pointer; } // transform stupid things like 'const void' or 'void const' into 'void' if (isVoid && type.referenceType == Type::NoReference) { type.name = "void"; } return type;}bool Moc::parseEnum(EnumDef *def){ if (!test(IDENTIFIER)) return false; // anonymous enum def->name = lexem(); if (!test(LBRACE)) return false; do { if (lookup() == RBRACE) // accept trailing comma break; next(IDENTIFIER); def->values += lexem(); } while (test(EQ) ? until(COMMA) : test(COMMA)); next(RBRACE); return true;}void Moc::parseFunctionArguments(FunctionDef *def){ Q_UNUSED(def); while (hasNext()) { ArgumentDef arg; arg.type = parseType(); if (arg.type.name == "void") break; if (test(IDENTIFIER)) arg.name = lexem(); while (test(LBRACK)) { arg.rightType += lexemUntil(RBRACK); } if (test(CONST) || test(VOLATILE)) { arg.rightType += ' '; arg.rightType += lexem(); } arg.normalizedType = normalizeType(arg.type.name + ' ' + arg.rightType); arg.typeNameForCast = normalizeType(noRef(arg.type.name) + "(*)" + arg.rightType); if (test(EQ)) arg.isDefault = true; def->arguments += arg; if (!until(COMMA)) break; }}// returns false if the function should be ignoredbool Moc::parseFunction(FunctionDef *def, bool inMacro){ def->isVirtual = false; while (test(INLINE) || test(STATIC) || test(VIRTUAL)) { if (lookup() == VIRTUAL) def->isVirtual = true; } bool templateFunction = (lookup() == TEMPLATE); def->type = parseType(); if (def->type.name.isEmpty()) { if (templateFunction) error("Template function as signal or slot"); else error(); } bool scopedFunctionName = false; if (test(LPAREN)) { def->name = def->type.name; scopedFunctionName = def->type.isScoped; def->type = Type("int"); } else { Type tempType = parseType();; while (!tempType.name.isEmpty() && lookup() != LPAREN) { if (def->type.name == "QT_MOC_COMPAT" || def->type.name == "QT3_SUPPORT") def->isCompat = true; else if (def->type.name == "Q_INVOKABLE") def->isInvokable = true; else if (def->type.name == "Q_SCRIPTABLE") def->isInvokable = def->isScriptable = true; else if (def->type.name == "Q_SIGNAL") error(); else if (def->type.name == "Q_SLOT") error(); else { if (!def->tag.isEmpty()) def->tag += ' '; def->tag += def->type.name; } def->type = tempType; tempType = parseType(); } next(LPAREN, "Not a signal or slot declaration"); def->name = tempType.name; scopedFunctionName = tempType.isScoped; } // we don't support references as return types, it's too dangerous if (def->type.referenceType == Type::Reference) def->type = Type("void"); def->normalizedType = normalizeType(def->type.name); if (!test(RPAREN)) { parseFunctionArguments(def); next(RPAREN); } // support optional macros with compiler specific options while (test(IDENTIFIER)) ; def->isConst = test(CONST); while (test(IDENTIFIER)) ; if (inMacro) { next(RPAREN); } else { if (test(SEMIC)) ; else if ((def->inlineCode = test(LBRACE))) until(RBRACE); else if (test(EQ) || test(THROW)) until(SEMIC); else error(); } if (scopedFunctionName) { QByteArray msg("Function declaration "); msg += def->name; msg += " contains extra qualification. Ignoring as signal or slot."; warning(msg.constData()); return false; } return true;}// like parseFunction, but never aborts with an errorbool Moc::parseMaybeFunction(FunctionDef *def){ def->type = parseType(); if (def->type.name.isEmpty()) return false; bool scopedFunctionName = false; if (test(LPAREN)) { def->name = def->type.name; scopedFunctionName = def->type.isScoped; def->type = Type("int"); } else { Type tempType = parseType();; while (!tempType.name.isEmpty() && lookup() != LPAREN) { if (def->type.name == "QT_MOC_COMPAT" || def->type.name == "QT3_SUPPORT") def->isCompat = true; else if (def->type.name == "Q_INVOKABLE") def->isInvokable = true; else if (def->type.name == "Q_SCRIPTABLE") def->isInvokable = def->isScriptable = true; else if (def->type.name == "Q_SIGNAL") def->isSignal = true; else if (def->type.name == "Q_SLOT") def->isSlot = true; else { if (!def->tag.isEmpty()) def->tag += ' '; def->tag += def->type.name; } def->type = tempType; tempType = parseType(); } if (!test(LPAREN)) return false; def->name = tempType.name; scopedFunctionName = tempType.isScoped; } // we don't support references as return types, it's too dangerous if (def->type.referenceType == Type::Reference) def->type = Type("void"); def->normalizedType = normalizeType(def->type.name); if (!test(RPAREN)) { parseFunctionArguments(def); if (!test(RPAREN)) return false; } def->isConst = test(CONST); if (scopedFunctionName && (def->isSignal || def->isSlot || def->isInvokable)) { QByteArray msg("parsemaybe: Function declaration "); msg += def->name; msg += " contains extra qualification. Ignoring as signal or slot."; warning(msg.constData()); return false; } return true;}void Moc::parse(){ currentFilenames.push(filename); QList<NamespaceDef> namespaceList; bool templateClass = false; while (hasNext()) { Token t = next(); switch (t) { case NAMESPACE: { int rewind = index; if (test(IDENTIFIER)) { if (test(EQ)) { // namespace Foo = Bar::Baz; until(SEMIC); } else if (!test(SEMIC)) { NamespaceDef def; def.name = lexem(); next(LBRACE); def.begin = index - 1; until(RBRACE); def.end = index; index = def.begin + 1; namespaceList += def; index = rewind; } } break; } case SEMIC: case RBRACE: templateClass = false; break; case TEMPLATE: templateClass = true; break; case MOC_INCLUDE_BEGIN: next(STRING_LITERAL); currentFilenames.push(symbol().unquotedLexem()); break; case MOC_INCLUDE_END: currentFilenames.pop(); break; case Q_DECLARE_INTERFACE_TOKEN: parseDeclareInterface(); break; case USING: if (test(NAMESPACE)) { while (test(SCOPE) || test(IDENTIFIER)) ; next(SEMIC); } break; default: break; } if (t != CLASS || currentFilenames.size() > 1) continue; ClassDef def; FunctionDef::Access access = FunctionDef::Private; if (parseClassHead(&def)) { for (int i = namespaceList.size() - 1; i >= 0; --i) if (inNamespace(&namespaceList.at(i))) def.qualified.prepend(namespaceList.at(i).name + "::"); while (inClass(&def) && hasNext()) { switch ((t = next())) { case PRIVATE: access = FunctionDef::Private; if (test(SIGNALS)) error("Signals cannot have access specifier"); break; case PROTECTED: access = FunctionDef::Protected; if (test(SIGNALS)) error("Signals cannot have access specifier"); break; case PUBLIC: access = FunctionDef::Public; if (test(SIGNALS)) error("Signals cannot have access specifier"); break; case CLASS: { ClassDef nestedDef; if (parseClassHead(&nestedDef)) { while (inClass(&nestedDef) && inClass(&def)) { t = next(); if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END) error("Meta object features not supported for nested classes"); } } } break; case SIGNALS: parseSignals(&def); break; case SLOTS: switch (lookup(-1)) { case PUBLIC: case PROTECTED: case PRIVATE: parseSlots(&def, access); break; default: error("Missing access specifier for slots"); } break; case Q_OBJECT_TOKEN: def.hasQObject = true; if (templateClass) error("Template classes not supported by Q_OBJECT"); if (def.classname != "Qt" && def.classname != "QObject" && def.superclassList.isEmpty()) error("Class contains Q_OBJECT macro but does not inherit from QObject"); break; case Q_GADGET_TOKEN: def.hasQGadget = true; if (templateClass) error("Template classes not supported by Q_GADGET"); break; case Q_PROPERTY_TOKEN: parseProperty(&def); break; case Q_ENUMS_TOKEN: parseEnumOrFlag(&def, false); break; case Q_FLAGS_TOKEN: parseEnumOrFlag(&def, true); break; case Q_DECLARE_FLAGS_TOKEN: parseFlag(&def); break; case Q_CLASSINFO_TOKEN: parseClassInfo(&def); break; case Q_INTERFACES_TOKEN: parseInterfaces(&def); break; case Q_PRIVATE_SLOT_TOKEN: parseSlotInPrivate(&def, access); break; case ENUM: { EnumDef enumDef; if (parseEnum(&enumDef)) def.enumList += enumDef; } break; default: FunctionDef funcDef; funcDef.access = access; int rewind = index; if (parseMaybeFunction(&funcDef)) { if (access == FunctionDef::Public) def.publicList += funcDef; if (funcDef.isSlot) { def.slotList += funcDef; while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) { funcDef.wasCloned = true; funcDef.arguments.removeLast(); def.slotList += funcDef; } } else if (funcDef.isSignal) { def.signalList += funcDef; while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) { funcDef.wasCloned = true; funcDef.arguments.removeLast(); def.signalList += funcDef; } } else if (funcDef.isInvokable) { def.methodList += funcDef;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -