diff options
-rw-r--r-- | codegen/analyzer.l | 17 | ||||
-rw-r--r-- | codegen/generator.cpp | 109 | ||||
-rw-r--r-- | codegen/generator.h | 35 | ||||
-rw-r--r-- | codegen/parser.y | 32 |
4 files changed, 167 insertions, 26 deletions
diff --git a/codegen/analyzer.l b/codegen/analyzer.l index de4b869..799ece3 100644 --- a/codegen/analyzer.l +++ b/codegen/analyzer.l @@ -1,5 +1,7 @@ /* - Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> + Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -29,6 +31,7 @@ void yyerror(CodeGen *codegen, const char *msg); id [a-zA-Z][a-zA-Z_0-9]* %x REGISTER_TYPE +%x REGISTER_WRAPPER %x ENUM %x ENUM_EAT_ASSIGNMENT %x INSTRUCTION @@ -41,7 +44,7 @@ id [a-zA-Z][a-zA-Z_0-9]* %% -<REGISTER_TYPE,ENUM,INSTRUCTION>{id} { yylval.Id = new QByteArray(yytext); return IDENTIFIER; } +<REGISTER_TYPE,REGISTER_WRAPPER,ENUM,INSTRUCTION>{id} { yylval.Id = new QByteArray(yytext); return IDENTIFIER; } QGLIB_REGISTER_TYPE\( { yy_push_state(REGISTER_TYPE); return REGISTER_TYPE_BEGIN; } <REGISTER_TYPE>{ @@ -51,6 +54,16 @@ QGLIB_REGISTER_TYPE\( { yy_push_state(REGISTER_TYPE); return REGISTER_TYPE_BE . { yyerror(codegen, "Syntax error in QGLIB_REGISTER_TYPE"); } } +Q[A-Z]+_WRAPPER\( { yy_push_state(REGISTER_WRAPPER); return REGISTER_WRAPPER_BEGIN; } +Q[A-Z]+_WRAPPER_DIFFERENT_C_CLASS\( { yy_push_state(REGISTER_WRAPPER); return REGISTER_WRAPPER_BEGIN; } +Q[A-Z]+_WRAPPER_FAKE_SUBCLASS\( { yy_push_state(REGISTER_WRAPPER); return REGISTER_WRAPPER_SUBCLASS_BEGIN; } +<REGISTER_WRAPPER>{ + , { return COMMA; } + \) { yy_pop_state(); return REGISTER_WRAPPER_END; } + [[:space:]]* + . { yyerror(codegen, "Syntax error in wrapper definition"); } +} + [[:space:]]enum { yy_push_state(ENUM); return ENUM_KEYWORD; } <ENUM>{ \{ { return LEFT_BRACE; } diff --git a/codegen/generator.cpp b/codegen/generator.cpp index 2d1033a..eb4bccb 100644 --- a/codegen/generator.cpp +++ b/codegen/generator.cpp @@ -1,5 +1,7 @@ /* - Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> + Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -24,6 +26,8 @@ extern int yylineno; int yyparse(CodeGen *codegen); void yyrestart(FILE *file); +QHash<QByteArray, QList<QByteArray> > CodeGen::s_wrapperDefinitions; + int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); @@ -36,16 +40,18 @@ int main(int argc, char *argv[]) if (fileName.startsWith("-I")) { outStream << "#include <" << fileName.remove(0, 2) << ">" << endl; } else if (fileName.endsWith(".h") && QFile::exists(fileName)) { - CodeGen::parse(fileName); + CodeGen::parse(fileName, outStream); } else { QTextStream(stderr) << "Skipping " << fileName << ": Not an existing header" << endl; } } + CodeGen::printGlobalWrapperDefinitions(outStream); + return 0; } -void CodeGen::parse(const QString & fileName) +void CodeGen::parse(const QString & fileName, QTextStream & outStream) { CodeGen codegen(fileName); @@ -61,19 +67,23 @@ void CodeGen::parse(const QString & fileName) yyparse(&codegen); std::fclose(fp); - codegen.generateOutput(); + codegen.generateOutput(outStream); } -void CodeGen::generateOutput() +void CodeGen::generateOutput(QTextStream & outStream) { - QTextStream outStream(stdout); outStream << "#include \"" << m_fileName << "\"" << endl << endl; - foreach(const TypeRegistration & typeReg, m_typeRegistrations) { + foreach(const QByteArrayHash & typeReg, m_typeRegistrations) { printTypeRegistration(outStream, typeReg); outStream << endl; } + foreach(const QByteArrayHash & def, m_wrapperDefinitions) { + printWrapperDefinition(outStream, def); + outStream << endl; + } + foreach(const Enum & enumDef, m_enums) { if (!enumDef.options.contains("skip")) { printEnumAssertions(outStream, enumDef); @@ -82,7 +92,7 @@ void CodeGen::generateOutput() } } -void CodeGen::printTypeRegistration(QTextStream & outStream, const TypeRegistration & typeReg) +void CodeGen::printTypeRegistration(QTextStream & outStream, const QByteArrayHash & typeReg) { outStream << "QGLIB_REGISTER_TYPE_IMPLEMENTATION("; @@ -96,7 +106,7 @@ void CodeGen::printTypeRegistration(QTextStream & outStream, const TypeRegistrat if (typeReg.contains("GType")) { outStream << typeReg["GType"]; } else { - outStream << (typeReg["namespace"] == "QGst" ? "GST_TYPE_" : "G_TYPE_"); + outStream << namespaceToGstStyle(typeReg["namespace"]) << "_TYPE_"; outStream << toGstStyle(typeReg["enum"].isEmpty() ? typeReg["class"] : typeReg["enum"]); } outStream << ")" << endl; @@ -117,7 +127,7 @@ void CodeGen::printEnumAssertions(QTextStream& outStream, const Enum & enumDef) if (enumDef.options.contains("prefix")) { outStream << enumDef.options["prefix"]; } else { - outStream << (enumDef.options["namespace"] == "QGst" ? "GST_" : "G_"); + outStream << namespaceToGstStyle(enumDef.options["namespace"]) << "_"; if (enumDef.options.contains("class") && !enumDef.options["class"].isEmpty()) { outStream << toGstStyle(enumDef.options["class"]) << "_"; } @@ -133,6 +143,59 @@ void CodeGen::printEnumAssertions(QTextStream& outStream, const Enum & enumDef) outStream << "}" << endl; } +void CodeGen::printWrapperDefinition(QTextStream& outStream, const QByteArrayHash & def) +{ + outStream << "namespace " << def["namespace"] << " {" << endl; + outStream << " QGlib::RefCountedObject *" << def["class"] << "_new(void *instance)" << endl; + outStream << " {" << endl; + + QByteArrayPair index = qMakePair(def["namespace"], def["class"]); + if (m_wrapperSubclasses.contains(index)) { + outStream << " switch(" << namespaceToGstStyle(def["namespace"]) + << "_" << toGstStyle(def["class"]) << "_" + << "TYPE(instance)) {" << endl; + + Q_FOREACH(const QByteArrayHash & subclass, m_wrapperSubclasses[index]) { + outStream << " case " << def["namespace"] << "::" + << def["class"] << subclass["prefix"] << ":" << endl; + outStream << " return new " << def["namespace"] << "::" + << subclass["prefix"] << def["class"] << ";" << endl; + } + + outStream << " default:" << endl; + outStream << " return new " << def["namespace"] << "::" << def["class"] << ";" << endl; + outStream << " }" << endl; + } else { + outStream << " Q_UNUSED(instance);" << endl; + outStream << " return new " << def["namespace"] << "::" << def["class"] << ";" << endl; + } + + outStream << " }" << endl; + outStream << "} //namespace " << def["namespace"] << endl; + + s_wrapperDefinitions[def["namespace"]].append(def["class"]); +} + +void CodeGen::printGlobalWrapperDefinitions(QTextStream & outStream) +{ + QHashIterator<QByteArray, QList<QByteArray> > it(s_wrapperDefinitions); + while (it.hasNext()) { + it.next(); + outStream << "namespace " << it.key() << " {" << endl; + outStream << " void registerWrapperConstructors()" << endl; + outStream << " {" << endl; + outStream << " QGlib::Quark q = g_quark_from_static_string(\"QGlib__wrapper_constructor\");" << endl; + + Q_FOREACH(const QByteArray & classId, it.value()) { + outStream << " QGlib::GetType<" << classId << ">()" + << ".setQuarkData(q, reinterpret_cast<void*>(&" << classId << "_new));" << endl; + } + outStream << " }" << endl; + outStream << "} //namespace " << it.key() << endl << endl; + } + s_wrapperDefinitions.clear(); +} + QByteArray CodeGen::toGstStyle(const QByteArray & str) { QByteArray output; @@ -149,8 +212,12 @@ QByteArray CodeGen::toGstStyle(const QByteArray & str) return output; } +QByteArray CodeGen::namespaceToGstStyle(const QByteArray & ns) +{ + return ns == "QGst" ? "GST" : "G"; +} -void CodeGen::addEnum(const QList<QByteArray> & values, const QHash<QByteArray, QByteArray> & options) +void CodeGen::addEnum(const QList<QByteArray> & values, const QByteArrayHash & options) { Enum e; e.values = values; @@ -161,15 +228,31 @@ void CodeGen::addEnum(const QList<QByteArray> & values, const QHash<QByteArray, } void CodeGen::addTypeRegistration(const QByteArray& namespaceId, const QByteArray& classId, - const QByteArray& enumId, const QHash<QByteArray, QByteArray>& options) + const QByteArray& enumId, const QByteArrayHash & options) { - TypeRegistration typeReg(options); + QByteArrayHash typeReg(options); typeReg["namespace"] = namespaceId; typeReg["class"] = classId; typeReg["enum"] = enumId; m_typeRegistrations.append(typeReg); } +void CodeGen::addWrapperDefinition(const QByteArray & classId, const QByteArrayHash & options) +{ + QByteArrayHash def(options); + def["namespace"] = m_currentNamespace; + def["class"] = classId; + m_wrapperDefinitions.append(def); +} + +void CodeGen::addWrapperFakeSubclass(const QByteArray & prefix, const QByteArray & classId, + const QByteArrayHash & options) +{ + QByteArrayHash sub(options); + sub["prefix"] = prefix; + m_wrapperSubclasses[qMakePair(m_currentNamespace, classId)].append(sub); +} + //called by yyerror() void CodeGen::fatalError(const char* msg) { diff --git a/codegen/generator.h b/codegen/generator.h index 58f054f..3108fc2 100644 --- a/codegen/generator.h +++ b/codegen/generator.h @@ -1,5 +1,7 @@ /* - Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> + Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -25,37 +27,52 @@ class CodeGen { public: - static void parse(const QString & fileName); + typedef QHash<QByteArray, QByteArray> QByteArrayHash; + typedef QPair<QByteArray, QByteArray> QByteArrayPair; + + static void parse(const QString & fileName, QTextStream & outStream); + static void printGlobalWrapperDefinitions(QTextStream & outStream); inline CodeGen(const QString & fileName) : m_fileName(fileName) {} inline void setCurrentNameSpace(const char *name) { m_currentNamespace = name; } inline void setCurrentClass(const char *name) { m_currentClass = name; } - void addEnum(const QList<QByteArray> & values, const QHash<QByteArray, QByteArray> & options); + void addEnum(const QList<QByteArray> & values, const QByteArrayHash & options); void addTypeRegistration(const QByteArray & namespaceId, const QByteArray & classId, - const QByteArray & enumId, const QHash<QByteArray, QByteArray> & options); + const QByteArray & enumId, const QByteArrayHash & options); + void addWrapperDefinition(const QByteArray & classId, const QByteArrayHash & options); + void addWrapperFakeSubclass(const QByteArray & prefix, const QByteArray & classId, + const QByteArrayHash & options); + void fatalError(const char *msg); private: struct Enum { QList<QByteArray> values; - QHash<QByteArray, QByteArray> options; + QByteArrayHash options; }; - typedef QHash<QByteArray, QByteArray> TypeRegistration; + void generateOutput(QTextStream & outStream); - void generateOutput(); - static void printTypeRegistration(QTextStream & outStream, const TypeRegistration & typeReg); + static void printTypeRegistration(QTextStream & outStream, const QByteArrayHash & typeReg); static void printEnumAssertions(QTextStream & outStream, const Enum & enumDef); + void printWrapperDefinition(QTextStream & outStream, const QByteArrayHash & def); + static QByteArray toGstStyle(const QByteArray & str); + static QByteArray namespaceToGstStyle(const QByteArray & ns); const QString m_fileName; QByteArray m_currentNamespace; QByteArray m_currentClass; QList<Enum> m_enums; - QList<TypeRegistration> m_typeRegistrations; + QList<QByteArrayHash> m_typeRegistrations; + QList<QByteArrayHash> m_wrapperDefinitions; + //< <namespace, class>, <prefix + options> > + QHash<QByteArrayPair, QList<QByteArrayHash> > m_wrapperSubclasses; + + static QHash<QByteArray, QList<QByteArray> > s_wrapperDefinitions; //<namespace, classes> }; #endif // GENERATOR_H diff --git a/codegen/parser.y b/codegen/parser.y index 29348cb..6c75bd2 100644 --- a/codegen/parser.y +++ b/codegen/parser.y @@ -1,5 +1,7 @@ /* - Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> + Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -31,6 +33,9 @@ void yyerror(CodeGen *codegen, const char *msg); %token REGISTER_TYPE_BEGIN SCOPE_RESOLUTION_OPERATOR REGISTER_TYPE_END + REGISTER_WRAPPER_BEGIN + REGISTER_WRAPPER_SUBCLASS_BEGIN + REGISTER_WRAPPER_END INSTRUCTIONS_BEGIN INSTRUCTIONS_ASSIGN_OPERATOR INSTRUCTIONS_SEPARATOR @@ -63,7 +68,7 @@ void yyerror(CodeGen *codegen, const char *msg); header: header expression | expression | /*empty*/; -expression : enum_def | type_registration; +expression : enum_def | type_registration | wrapper_definition; enum_def: ENUM_KEYWORD IDENTIFIER LEFT_BRACE optional_instructions enum_list RIGHT_BRACE SEMICOLON @@ -109,6 +114,29 @@ optional_enum_id: $$ = new QByteArray(); }; +wrapper_definition: + REGISTER_WRAPPER_BEGIN IDENTIFIER optional_c_class REGISTER_WRAPPER_END optional_instructions + { + codegen->addWrapperDefinition(*$2, *$5); + delete $2; + delete $5; + } + | + REGISTER_WRAPPER_SUBCLASS_BEGIN IDENTIFIER COMMA IDENTIFIER REGISTER_WRAPPER_END optional_instructions + { + codegen->addWrapperFakeSubclass(*$2, *$4, *$6); + delete $2; + delete $4; + delete $6; + }; + +optional_c_class: + COMMA IDENTIFIER + { + delete $2; + } + | /* empty */ + ; optional_instructions: INSTRUCTIONS_BEGIN instruction_list INSTRUCTIONS_END |