QmlCompiler: Implement Math.pow()

Also, add missing positive infinity to test data.

Pick-to: 6.4
Fixes: QTBUG-104745
Change-Id: I958aca672cca8cc83c540ed3ea75b08e70eb90fd
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ulf Hermann 2022-07-19 14:00:28 +02:00
parent eed7b3f4e7
commit e97f8cabc8
5 changed files with 46 additions and 3 deletions

View File

@ -280,5 +280,16 @@ QString QJSPrimitiveValue::toString(double d)
return result;
}
/*!
\fn double QQmlPrivate::jsExponentiate(double base, double exponent)
\internal
\since 6.4
Performs JavaScript's Number::exponentiate operation on \a base and
\a exponent, and returns the result.
See https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-exponentiate
*/
QT_END_NAMESPACE

View File

@ -783,6 +783,37 @@ private:
QJSPrimitiveValuePrivate d;
};
namespace QQmlPrivate {
// TODO: Make this constexpr once std::isnan is constexpr.
inline double jsExponentiate(double base, double exponent)
{
constexpr double qNaN = std::numeric_limits<double>::quiet_NaN();
constexpr double inf = std::numeric_limits<double>::infinity();
if (qIsNull(exponent))
return 1.0;
if (std::isnan(exponent))
return qNaN;
if (QJSNumberCoercion::equals(base, 1.0) || QJSNumberCoercion::equals(base, -1.0))
return std::isinf(exponent) ? qNaN : std::pow(base, exponent);
if (!qIsNull(base))
return std::pow(base, exponent);
if (std::copysign(1.0, base) > 0.0)
return exponent < 0.0 ? inf : std::pow(base, exponent);
if (exponent < 0.0)
return QJSNumberCoercion::equals(std::fmod(-exponent, 2.0), 1.0) ? -inf : inf;
return QJSNumberCoercion::equals(std::fmod(exponent, 2.0), 1.0)
? std::copysign(0, -1.0)
: 0.0;
}
}
QT_END_NAMESPACE
#endif // QJSPRIMITIVEVALUE_H

View File

@ -1320,6 +1320,7 @@ bool QQmlJSCodeGenerator::inlineMathMethod(const QString &name, int argc, int ar
addInclude(u"limits"_s);
addInclude(u"qalgorithms.h"_s);
addInclude(u"qrandom.h"_s);
addInclude(u"qjsprimitivevalue.h"_s);
// If the result is not stored, we don't need to generate any code. All the math methods are
// conceptually pure functions.
@ -1403,8 +1404,7 @@ bool QQmlJSCodeGenerator::inlineMathMethod(const QString &name, int argc, int ar
"? arg2 "
": ((arg2 < arg1 || std::isnan(arg2)) ? arg2 : arg1)"_s;
} else if (name == u"pow"_s) {
// TODO: complicated
return false;
expression = u"QQmlPrivate::jsExponentiate(arg1, arg2)"_s;
} else if (name == u"random"_s && argc == 0) {
expression = u"QRandomGenerator::global()->generateDouble()"_s;
} else if (name == u"round"_s && argc == 1) {

View File

@ -32,7 +32,7 @@ QtObject {
property double log2: Math.log2(a)
property double max: Math.max(a, b)
property double min: Math.min(a, b)
// property double pow: Math.pow(a, b)
property double pow: Math.pow(a, b)
property double random: Math.random()
property double round: Math.round(a)
property double sign: Math.sign(a)

View File

@ -1606,6 +1606,7 @@ void tst_QmlCppCodegen::jsMathObject()
std::numeric_limits<quint32>::max(),
std::numeric_limits<float>::max(),
std::numeric_limits<double>::max(),
qInf()
};
QJSManagedValue math(engine.globalObject().property(QStringLiteral("Math")), &engine);