mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 15:59:49 +02:00
Added scoring system for determining overloaded function to call
This commit is contained in:
parent
f926e8d30c
commit
def8555b99
3 changed files with 125 additions and 13 deletions
|
@ -152,6 +152,7 @@ public: // not for public use, but I don't like how Qt strings this along with p
|
||||||
virtual QVariant convert(const ScriptValue& value, int typeId) override;
|
virtual QVariant convert(const ScriptValue& value, int typeId) override;
|
||||||
virtual void registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc,
|
virtual void registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc,
|
||||||
ScriptEngine::DemarshalFunction demarshalFunc) override;
|
ScriptEngine::DemarshalFunction demarshalFunc) override;
|
||||||
|
int computeCastPenalty(QScriptValue& val, int destTypeId);
|
||||||
bool castValueToVariant(const QScriptValue& val, QVariant& dest, int destTypeId);
|
bool castValueToVariant(const QScriptValue& val, QVariant& dest, int destTypeId);
|
||||||
QScriptValue castVariantToValue(const QVariant& val);
|
QScriptValue castVariantToValue(const QVariant& val);
|
||||||
static QString valueType(const QScriptValue& val);
|
static QString valueType(const QScriptValue& val);
|
||||||
|
|
|
@ -195,6 +195,87 @@ void ScriptEngineQtScript::registerSystemTypes() {
|
||||||
scriptRegisterMetaType<QJsonArray, JsonArrayToScriptValue, JsonArrayFromScriptValue>(this);
|
scriptRegisterMetaType<QJsonArray, JsonArrayToScriptValue, JsonArrayFromScriptValue>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ScriptEngineQtScript::computeCastPenalty(QScriptValue& val, int destTypeId) {
|
||||||
|
if (val.isNumber()) {
|
||||||
|
switch (destTypeId){
|
||||||
|
case QMetaType::Bool:
|
||||||
|
return 5;
|
||||||
|
break;
|
||||||
|
case QMetaType::UInt:
|
||||||
|
case QMetaType::ULong:
|
||||||
|
case QMetaType::Int:
|
||||||
|
case QMetaType::Long:
|
||||||
|
case QMetaType::Short:
|
||||||
|
case QMetaType::Double:
|
||||||
|
case QMetaType::Float:
|
||||||
|
case QMetaType::ULongLong:
|
||||||
|
case QMetaType::LongLong:
|
||||||
|
case QMetaType::UShort:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case QMetaType::QString:
|
||||||
|
case QMetaType::QByteArray:
|
||||||
|
case QMetaType::QDateTime:
|
||||||
|
case QMetaType::QDate:
|
||||||
|
return 100;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
} else if (val.isString() || val.isDate() || val.isRegExp()) {
|
||||||
|
switch (destTypeId){
|
||||||
|
case QMetaType::Bool:
|
||||||
|
return 100;
|
||||||
|
case QMetaType::UInt:
|
||||||
|
case QMetaType::ULong:
|
||||||
|
case QMetaType::Int:
|
||||||
|
case QMetaType::Long:
|
||||||
|
case QMetaType::Short:
|
||||||
|
case QMetaType::Double:
|
||||||
|
case QMetaType::Float:
|
||||||
|
case QMetaType::ULongLong:
|
||||||
|
case QMetaType::LongLong:
|
||||||
|
case QMetaType::UShort:
|
||||||
|
return 100;
|
||||||
|
case QMetaType::QString:
|
||||||
|
return 0;
|
||||||
|
case QMetaType::QByteArray:
|
||||||
|
case QMetaType::QDateTime:
|
||||||
|
case QMetaType::QDate:
|
||||||
|
return 5;
|
||||||
|
default:
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
} else if (val.isBool() || val.isBoolean()) {
|
||||||
|
switch (destTypeId){
|
||||||
|
case QMetaType::Bool:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case QMetaType::UInt:
|
||||||
|
case QMetaType::ULong:
|
||||||
|
case QMetaType::Int:
|
||||||
|
case QMetaType::Long:
|
||||||
|
case QMetaType::Short:
|
||||||
|
case QMetaType::Double:
|
||||||
|
case QMetaType::Float:
|
||||||
|
case QMetaType::ULongLong:
|
||||||
|
case QMetaType::LongLong:
|
||||||
|
case QMetaType::UShort:
|
||||||
|
return 5;
|
||||||
|
break;
|
||||||
|
case QMetaType::QString:
|
||||||
|
case QMetaType::QByteArray:
|
||||||
|
case QMetaType::QDateTime:
|
||||||
|
case QMetaType::QDate:
|
||||||
|
return 50;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool ScriptEngineQtScript::castValueToVariant(const QScriptValue& val, QVariant& dest, int destTypeId) {
|
bool ScriptEngineQtScript::castValueToVariant(const QScriptValue& val, QVariant& dest, int destTypeId) {
|
||||||
|
|
||||||
// if we're not particularly interested in a specific type, try to detect if we're dealing with a registered type
|
// if we're not particularly interested in a specific type, try to detect if we're dealing with a registered type
|
||||||
|
|
|
@ -462,38 +462,51 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg
|
||||||
int parameterConversionFailureId = 0;
|
int parameterConversionFailureId = 0;
|
||||||
int parameterConversionFailureCount = 0;
|
int parameterConversionFailureCount = 0;
|
||||||
|
|
||||||
for (auto iter = _metas.cbegin(); iter != _metas.end(); ++iter) {
|
int num_metas = _metas.size();
|
||||||
const QMetaMethod& meta = *iter;
|
QVector< QList<ScriptValue> > qScriptArgLists;
|
||||||
|
QVector< QVector <QGenericArgument> > qGenArgsVectors;
|
||||||
|
QVector< QList<QVariant> > qVarArgLists;
|
||||||
|
int conversionPenaltyScore[num_metas];
|
||||||
|
bool isMetaRejected[num_metas];
|
||||||
|
qScriptArgLists.resize(num_metas);
|
||||||
|
qGenArgsVectors.resize(num_metas);
|
||||||
|
qVarArgLists.resize(num_metas);
|
||||||
|
|
||||||
|
for (int i = 0; i < num_metas; i++) {
|
||||||
|
const QMetaMethod& meta = _metas[i];
|
||||||
|
isMetaRejected[i] = false;
|
||||||
int methodNumArgs = meta.parameterCount();
|
int methodNumArgs = meta.parameterCount();
|
||||||
if (methodNumArgs != numArgs) {
|
if (methodNumArgs != numArgs) {
|
||||||
|
isMetaRejected[i] = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ScriptValue> qScriptArgList;
|
qGenArgsVectors[i].resize(10);
|
||||||
QList<QVariant> qVarArgList;
|
conversionPenaltyScore[i] = 0;
|
||||||
QGenericArgument qGenArgs[10];
|
|
||||||
int conversionFailures = 0;
|
int conversionFailures = 0;
|
||||||
|
|
||||||
for (int arg = 0; arg < numArgs; ++arg) {
|
for (int arg = 0; arg < numArgs; ++arg) {
|
||||||
int methodArgTypeId = meta.parameterType(arg);
|
int methodArgTypeId = meta.parameterType(arg);
|
||||||
Q_ASSERT(methodArgTypeId != QMetaType::UnknownType);
|
Q_ASSERT(methodArgTypeId != QMetaType::UnknownType);
|
||||||
QScriptValue argVal = context->argument(arg);
|
QScriptValue argVal = context->argument(arg);
|
||||||
if (methodArgTypeId == scriptValueTypeId) {
|
if (methodArgTypeId == scriptValueTypeId) {
|
||||||
qScriptArgList.append(ScriptValue(new ScriptValueQtWrapper(_engine, argVal)));
|
qScriptArgLists[i].append(ScriptValue(new ScriptValueQtWrapper(_engine, argVal)));
|
||||||
qGenArgs[arg] = Q_ARG(ScriptValue, qScriptArgList.back());
|
qGenArgsVectors[i][arg] = Q_ARG(ScriptValue, qScriptArgLists[i].back());
|
||||||
} else if (methodArgTypeId == QMetaType::QVariant) {
|
} else if (methodArgTypeId == QMetaType::QVariant) {
|
||||||
qVarArgList.append(argVal.toVariant());
|
qVarArgLists[i].append(argVal.toVariant());
|
||||||
qGenArgs[arg] = Q_ARG(QVariant, qVarArgList.back());
|
qGenArgsVectors[i][arg] = Q_ARG(QVariant, qVarArgLists[i].back());
|
||||||
} else {
|
} else {
|
||||||
QVariant varArgVal;
|
QVariant varArgVal;
|
||||||
if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) {
|
if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) {
|
||||||
conversionFailures++;
|
conversionFailures++;
|
||||||
} else {
|
} else {
|
||||||
qVarArgList.append(varArgVal);
|
qVarArgLists[i].append(varArgVal);
|
||||||
const QVariant& converted = qVarArgList.back();
|
const QVariant& converted = qVarArgLists[i].back();
|
||||||
|
conversionPenaltyScore[i] = _engine->computeCastPenalty(argVal, methodArgTypeId);
|
||||||
|
|
||||||
// a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant
|
// a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant
|
||||||
// A const_cast is needed because calling data() would detach the QVariant.
|
// A const_cast is needed because calling data() would detach the QVariant.
|
||||||
qGenArgs[arg] =
|
qGenArgsVectors[i][arg] =
|
||||||
QGenericArgument(QMetaType::typeName(converted.userType()), const_cast<void*>(converted.constData()));
|
QGenericArgument(QMetaType::typeName(converted.userType()), const_cast<void*>(converted.constData()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -503,13 +516,30 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg
|
||||||
parameterConversionFailureCount = conversionFailures;
|
parameterConversionFailureCount = conversionFailures;
|
||||||
parameterConversionFailureId = meta.methodIndex();
|
parameterConversionFailureId = meta.methodIndex();
|
||||||
}
|
}
|
||||||
|
isMetaRejected[i] = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptContextQtWrapper ourContext(_engine, context);
|
ScriptContextQtWrapper ourContext(_engine, context);
|
||||||
ScriptContextGuard guard(&ourContext);
|
ScriptContextGuard guard(&ourContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValidMetaSelected = false;
|
||||||
|
int bestMeta = 0;
|
||||||
|
for (int i = 0; i < num_metas; i++) {
|
||||||
|
if (!isValidMetaSelected && !isMetaRejected[i]) {
|
||||||
|
isValidMetaSelected = true;
|
||||||
|
bestMeta = i;
|
||||||
|
}
|
||||||
|
if (isValidMetaSelected && !isMetaRejected[i] && conversionPenaltyScore[bestMeta] > conversionPenaltyScore[i]) {
|
||||||
|
bestMeta = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isValidMetaSelected) {
|
||||||
|
const QMetaMethod& meta = _metas[bestMeta];
|
||||||
int returnTypeId = meta.returnType();
|
int returnTypeId = meta.returnType();
|
||||||
|
QVector <QGenericArgument> &qGenArgs = qGenArgsVectors[bestMeta];
|
||||||
|
|
||||||
// The Qt MOC engine will automatically call qRegisterMetaType on invokable parameters and properties, but there's
|
// The Qt MOC engine will automatically call qRegisterMetaType on invokable parameters and properties, but there's
|
||||||
// nothing in there for return values so these need to be explicitly runtime-registered!
|
// nothing in there for return values so these need to be explicitly runtime-registered!
|
||||||
|
@ -579,9 +609,9 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context->throwError(QString("Native call of %1 failed: could not locate an overload with the requested arguments").arg(fullName()));
|
||||||
Q_ASSERT(false); // really shouldn't have gotten here -- it didn't work before and it's working now?
|
Q_ASSERT(false); // really shouldn't have gotten here -- it didn't work before and it's working now?
|
||||||
return QVariant();
|
return QVariant();
|
||||||
context->throwError(QString("Native call of %1 failed: could not locate an overload with the requested arguments").arg(fullName()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ScriptSignalQtProxy::fullName() const {
|
QString ScriptSignalQtProxy::fullName() const {
|
||||||
|
|
Loading…
Reference in a new issue