summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Kiagiadakis <george.kiagiadakis@collabora.co.uk>2011-01-03 12:54:58 +0200
committerGeorge Kiagiadakis <george.kiagiadakis@collabora.co.uk>2011-01-03 12:54:58 +0200
commit503a8389a48057b8360ccc17f899204fe9273c85 (patch)
treeb64f24ab26b0f6be39ec29586f6095f98eaaacd3
parent1e16778c2abe392428ab7d3c7a33dcc88d7eb0a9 (diff)
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.
-rw-r--r--codegen/analyzer.l17
-rw-r--r--codegen/generator.cpp109
-rw-r--r--codegen/generator.h35
-rw-r--r--codegen/parser.y32
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