blob: a126f365694e494d0bfa63712e540d4db4f593b5 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2017 Ford Motor Company
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtRemoteObjects module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "utils.h"
#include "repparser.h"
#include <moc.h>
#define _(X) QString::fromLatin1(X)
QT_BEGIN_NAMESPACE
static QByteArray join(const QVector<QByteArray> &array, const QByteArray &separator)
{
QByteArray res;
const int sz = array.size();
if (!sz)
return res;
for (int i = 0; i < sz - 1; i++)
res += array.at(i) + separator;
res += array.at(sz - 1);
return res;
}
static QVector<QByteArray> generateProperties(const QVector<PropertyDef> &properties, bool isPod=false)
{
QVector<QByteArray> ret;
for (const PropertyDef& property : properties) {
if (!isPod && property.notifyId == -1 && !property.constant) {
qWarning() << "Skipping property" << property.name << "because is non-notifiable & non-constant";
continue; // skip non-notifiable properties
}
QByteArray prop = property.type + " " + property.name;
if (property.constant)
prop += " CONSTANT";
if (property.write.isEmpty() && !property.read.isEmpty())
prop += " READONLY";
ret << prop;
}
return ret;
}
static QByteArray generateFunctions(const QByteArray &type, const QVector<FunctionDef> &functionList)
{
QByteArray ret;
for (const FunctionDef &func : functionList) {
if (func.access != FunctionDef::Public)
continue;
ret += type + "(" + func.normalizedType + " " + func.name + "(";
const int sz = func.arguments.size();
if (sz) {
for (int i = 0; i < sz - 1 ; i++) {
const ArgumentDef &arg = func.arguments.at(i);
ret += arg.normalizedType + " " + arg.name + ", ";
}
const ArgumentDef &arg = func.arguments.at(sz -1);
ret += arg.normalizedType + " " + arg.name;
}
ret += "));\n";
}
return ret;
}
static bool highToLowSort(int a, int b)
{
return a > b;
}
static QVector<FunctionDef> cleanedSignalList(const ClassDef &cdef)
{
auto ret = cdef.signalList;
QVector<int> positions;
for (const PropertyDef &prop : qAsConst(cdef.propertyList)) {
if (prop.notifyId != -1) {
Q_ASSERT(prop.notify == ret.at(prop.notifyId).name);
positions.push_back(prop.notifyId);
}
}
std::sort(positions.begin(), positions.end(), highToLowSort);
for (int pos : qAsConst(positions))
ret.removeAt(pos);
return ret;
}
static QVector<FunctionDef> cleanedSlotList(const ClassDef &cdef)
{
auto ret = cdef.slotList;
for (const PropertyDef &prop : qAsConst(cdef.propertyList)) {
if (!prop.write.isEmpty()) {
auto it = ret.begin();
while (it != ret.end()) {
const FunctionDef& fdef = *it;
if (fdef.name == prop.write &&
fdef.arguments.size() == 1 &&
fdef.arguments[0].type.name == prop.type) {
ret.erase(it);
break;
}
++it;
}
}
}
return ret;
}
QByteArray generateClass(const ClassDef &cdef, bool alwaysGenerateClass /* = false */)
{
const auto signalList = cleanedSignalList(cdef);
if (signalList.isEmpty() && cdef.slotList.isEmpty() && !alwaysGenerateClass)
return "POD " + cdef.classname + "(" + join(generateProperties(cdef.propertyList, true), ", ") + ")\n";
QByteArray ret("class " + cdef.classname + "\n{\n");
if (!cdef.propertyList.isEmpty())
ret += " PROP(" + join(generateProperties(cdef.propertyList), ");\n PROP(") + ");\n";
ret += generateFunctions(" SLOT", cleanedSlotList(cdef));
ret += generateFunctions(" SIGNAL", signalList);
ret += "}\n";
return ret;
}
static QVector<PODAttribute> propertyList2PODAttributes(const QVector<PropertyDef> &list)
{
QVector<PODAttribute> ret;
for (const PropertyDef &prop : list)
ret.push_back(PODAttribute(_(prop.type), _(prop.name)));
return ret;
}
QVector<ASTProperty> propertyList2AstProperties(const QVector<PropertyDef> &list)
{
QVector<ASTProperty> ret;
for (const PropertyDef &property : list) {
if (property.notifyId == -1 && !property.constant) {
qWarning() << "Skipping property" << property.name << "because is non-notifiable & non-constant";
continue; // skip non-notifiable properties
}
ASTProperty prop;
prop.name = _(property.name);
prop.type = _(property.type);
prop.modifier = property.constant
? ASTProperty::Constant
: property.write.isEmpty() && !property.read.isEmpty()
? ASTProperty::ReadOnly
: ASTProperty::ReadWrite;
ret.push_back(prop);
}
return ret;
}
QVector<ASTFunction> functionList2AstFunctionList(const QVector<FunctionDef> &list)
{
QVector<ASTFunction> ret;
for (const FunctionDef &fdef : list) {
if (fdef.access != FunctionDef::Public)
continue;
ASTFunction func;
func.name = _(fdef.name);
func.returnType = _(fdef.type.name);
for (const ArgumentDef &arg : fdef.arguments)
func.params.push_back(ASTDeclaration(_(arg.type.name), _(arg.name)));
ret.push_back(func);
}
return ret;
}
AST classList2AST(const QVector<ClassDef> &classList)
{
AST ret;
for (const ClassDef &cdef : classList) {
const auto signalList = cleanedSignalList(cdef);
if (signalList.isEmpty() && cdef.slotList.isEmpty()) {
POD pod;
pod.name = _(cdef.classname);
pod.attributes = propertyList2PODAttributes(cdef.propertyList);
ret.pods.push_back(pod);
} else {
ASTClass cl(_(cdef.classname));
cl.properties = propertyList2AstProperties(cdef.propertyList);
cl.signalsList = functionList2AstFunctionList(signalList);
cl.slotsList = functionList2AstFunctionList(cleanedSlotList(cdef));
ret.classes.push_back(cl);
}
}
return ret;
}
QT_END_NAMESPACE