summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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