mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 09:33:49 +02:00
Added scoring system for determining overloaded function to call
This commit is contained in:
parent
8304a0c500
commit
979e9ff113
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 void registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc,
|
||||
ScriptEngine::DemarshalFunction demarshalFunc) override;
|
||||
int computeCastPenalty(QScriptValue& val, int destTypeId);
|
||||
bool castValueToVariant(const QScriptValue& val, QVariant& dest, int destTypeId);
|
||||
QScriptValue castVariantToValue(const QVariant& val);
|
||||
static QString valueType(const QScriptValue& val);
|
||||
|
|
|
@ -195,6 +195,87 @@ void ScriptEngineQtScript::registerSystemTypes() {
|
|||
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) {
|
||||
|
||||
// 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 parameterConversionFailureCount = 0;
|
||||
|
||||
for (auto iter = _metas.cbegin(); iter != _metas.end(); ++iter) {
|
||||
const QMetaMethod& meta = *iter;
|
||||
int num_metas = _metas.size();
|
||||
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();
|
||||
if (methodNumArgs != numArgs) {
|
||||
isMetaRejected[i] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
QList<ScriptValue> qScriptArgList;
|
||||
QList<QVariant> qVarArgList;
|
||||
QGenericArgument qGenArgs[10];
|
||||
qGenArgsVectors[i].resize(10);
|
||||
conversionPenaltyScore[i] = 0;
|
||||
int conversionFailures = 0;
|
||||
|
||||
for (int arg = 0; arg < numArgs; ++arg) {
|
||||
int methodArgTypeId = meta.parameterType(arg);
|
||||
Q_ASSERT(methodArgTypeId != QMetaType::UnknownType);
|
||||
QScriptValue argVal = context->argument(arg);
|
||||
if (methodArgTypeId == scriptValueTypeId) {
|
||||
qScriptArgList.append(ScriptValue(new ScriptValueQtWrapper(_engine, argVal)));
|
||||
qGenArgs[arg] = Q_ARG(ScriptValue, qScriptArgList.back());
|
||||
qScriptArgLists[i].append(ScriptValue(new ScriptValueQtWrapper(_engine, argVal)));
|
||||
qGenArgsVectors[i][arg] = Q_ARG(ScriptValue, qScriptArgLists[i].back());
|
||||
} else if (methodArgTypeId == QMetaType::QVariant) {
|
||||
qVarArgList.append(argVal.toVariant());
|
||||
qGenArgs[arg] = Q_ARG(QVariant, qVarArgList.back());
|
||||
qVarArgLists[i].append(argVal.toVariant());
|
||||
qGenArgsVectors[i][arg] = Q_ARG(QVariant, qVarArgLists[i].back());
|
||||
} else {
|
||||
QVariant varArgVal;
|
||||
if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) {
|
||||
conversionFailures++;
|
||||
} else {
|
||||
qVarArgList.append(varArgVal);
|
||||
const QVariant& converted = qVarArgList.back();
|
||||
qVarArgLists[i].append(varArgVal);
|
||||
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 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()));
|
||||
}
|
||||
}
|
||||
|
@ -503,13 +516,30 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg
|
|||
parameterConversionFailureCount = conversionFailures;
|
||||
parameterConversionFailureId = meta.methodIndex();
|
||||
}
|
||||
isMetaRejected[i] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
ScriptContextQtWrapper ourContext(_engine, context);
|
||||
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();
|
||||
QVector <QGenericArgument> &qGenArgs = qGenArgsVectors[bestMeta];
|
||||
|
||||
// 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!
|
||||
|
@ -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?
|
||||
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 {
|
||||
|
|
Loading…
Reference in a new issue