From 503a8389a48057b8360ccc17f899204fe9273c85 Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Mon, 3 Jan 2011 12:54:58 +0200 Subject: Modify codegen to generate wrapper constructor functions. These functions offer some kind of reflection in our bindings. They are attached on the GType qdata and so they can be used to construct the correct subclass given the GType of an instance. --- codegen/analyzer.l | 17 +++++++- codegen/generator.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++------ codegen/generator.h | 35 +++++++++++----- 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 + Copyright (C) 2010 George Kiagiadakis + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis 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]* %% -{id} { yylval.Id = new QByteArray(yytext); return IDENTIFIER; } +{id} { yylval.Id = new QByteArray(yytext); return IDENTIFIER; } QGLIB_REGISTER_TYPE\( { yy_push_state(REGISTER_TYPE); return REGISTER_TYPE_BEGIN; } { @@ -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; } +{ + , { 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; } { \{ { 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 + Copyright (C) 2010 George Kiagiadakis + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis 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 > 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 > 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(&" << 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 & values, const QHash & options) +void CodeGen::addEnum(const QList & values, const QByteArrayHash & options) { Enum e; e.values = values; @@ -161,15 +228,31 @@ void CodeGen::addEnum(const QList & values, const QHash& 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 + Copyright (C) 2010 George Kiagiadakis + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis 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 QByteArrayHash; + typedef QPair 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 & values, const QHash & options); + void addEnum(const QList & values, const QByteArrayHash & options); void addTypeRegistration(const QByteArray & namespaceId, const QByteArray & classId, - const QByteArray & enumId, const QHash & 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 values; - QHash options; + QByteArrayHash options; }; - typedef QHash 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 m_enums; - QList m_typeRegistrations; + QList m_typeRegistrations; + QList m_wrapperDefinitions; + //< , > + QHash > m_wrapperSubclasses; + + static QHash > s_wrapperDefinitions; // }; #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 + Copyright (C) 2010 George Kiagiadakis + Copyright (C) 2010 Collabora Ltd. + @author George Kiagiadakis 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 -- cgit v1.2.3