Add some ECMAScript 6 Number and Math methods and properties

This adds the Number.EPSILON property, the Number.isFinite, Number.isNaN,
and Math.sign methods introduced in ECMAScript 6.

Change-Id: Ib16408a63c202a4ef30a14334f65ac3a1a13cfaf
Reviewed-by: Michael Brasser <michael.brasser@live.com>
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
This commit is contained in:
Kai Uwe Broulik 2016-04-13 12:53:30 +02:00
parent 9e44c5594f
commit 7a0f3269b1
6 changed files with 98 additions and 0 deletions

View File

@ -231,6 +231,15 @@
\li \l {Number::toLocaleString}{toLocaleString(locale, format, precision)}
\endlist
\section2 The Number Object
\section3 Function Properties
\list
\li isFinite(x) // ECMAScript 6: Added in Qt 5.8
\li isNaN(x) // ECMAScript 6: Added in Qt 5.8
\endlist
\section1 The Math Object
\section2 Value Properties
@ -264,6 +273,7 @@
\li pow(x, y)
\li random()
\li round(x)
\li sign(x) // ECMAScript 6: Added in Qt 5.8
\li sin(x)
\li sqrt(x)
\li tan(x)

View File

@ -80,6 +80,7 @@ Heap::MathObject::MathObject()
m->defineDefaultProperty(QStringLiteral("pow"), QV4::MathObject::method_pow, 2);
m->defineDefaultProperty(QStringLiteral("random"), QV4::MathObject::method_random, 0);
m->defineDefaultProperty(QStringLiteral("round"), QV4::MathObject::method_round, 1);
m->defineDefaultProperty(QStringLiteral("sign"), QV4::MathObject::method_sign, 1);
m->defineDefaultProperty(QStringLiteral("sin"), QV4::MathObject::method_sin, 1);
m->defineDefaultProperty(QStringLiteral("sqrt"), QV4::MathObject::method_sqrt, 1);
m->defineDefaultProperty(QStringLiteral("tan"), QV4::MathObject::method_tan, 1);
@ -299,6 +300,19 @@ ReturnedValue MathObject::method_round(CallContext *context)
return Encode(v);
}
ReturnedValue MathObject::method_sign(CallContext *context)
{
double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
if (std::isnan(v))
return Encode(qt_qnan());
if (qIsNull(v))
return v;
return Encode(std::signbit(v) ? -1 : 1);
}
ReturnedValue MathObject::method_sin(CallContext *context)
{
double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();

View File

@ -84,6 +84,7 @@ struct MathObject: Object
static ReturnedValue method_pow(CallContext *context);
static ReturnedValue method_random(CallContext *context);
static ReturnedValue method_round(CallContext *context);
static ReturnedValue method_sign(CallContext *context);
static ReturnedValue method_sin(CallContext *context);
static ReturnedValue method_sqrt(CallContext *context);
static ReturnedValue method_tan(CallContext *context);

View File

@ -45,6 +45,7 @@
#include <QtCore/qmath.h>
#include <QtCore/QDebug>
#include <cassert>
#include <limits>
using namespace QV4;
@ -99,12 +100,16 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor)
ctor->defineReadonlyProperty(QStringLiteral("NEGATIVE_INFINITY"), Primitive::fromDouble(-qInf()));
ctor->defineReadonlyProperty(QStringLiteral("POSITIVE_INFINITY"), Primitive::fromDouble(qInf()));
ctor->defineReadonlyProperty(QStringLiteral("MAX_VALUE"), Primitive::fromDouble(1.7976931348623158e+308));
ctor->defineReadonlyProperty(QStringLiteral("EPSILON"), Primitive::fromDouble(std::numeric_limits<double>::epsilon()));
QT_WARNING_PUSH
QT_WARNING_DISABLE_INTEL(239)
ctor->defineReadonlyProperty(QStringLiteral("MIN_VALUE"), Primitive::fromDouble(5e-324));
QT_WARNING_POP
ctor->defineDefaultProperty(QStringLiteral("isFinite"), method_isFinite, 1);
ctor->defineDefaultProperty(QStringLiteral("isNaN"), method_isNaN, 1);
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString);
defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString);
@ -134,6 +139,24 @@ inline double thisNumber(ExecutionContext *ctx)
return n->value();
}
ReturnedValue NumberPrototype::method_isFinite(CallContext *ctx)
{
if (!ctx->argc())
return Encode(false);
double v = ctx->args()[0].toNumber();
return Encode(!std::isnan(v) && !qt_is_inf(v));
}
ReturnedValue NumberPrototype::method_isNaN(CallContext *ctx)
{
if (!ctx->argc())
return Encode(false);
double v = ctx->args()[0].toNumber();
return Encode(std::isnan(v));
}
ReturnedValue NumberPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);

View File

@ -87,6 +87,8 @@ struct NumberPrototype: NumberObject
{
void init(ExecutionEngine *engine, Object *ctor);
static ReturnedValue method_isFinite(CallContext *ctx);
static ReturnedValue method_isNaN(CallContext *ctx);
static ReturnedValue method_toString(CallContext *ctx);
static ReturnedValue method_toLocaleString(CallContext *ctx);
static ReturnedValue method_valueOf(CallContext *ctx);

View File

@ -1024,11 +1024,14 @@ void tst_QJSEngine::builtinFunctionNames_data()
QTest::newRow("Math.pow") << QString("Math.pow") << QString("pow");
QTest::newRow("Math.random") << QString("Math.random") << QString("random");
QTest::newRow("Math.round") << QString("Math.round") << QString("round");
QTest::newRow("Math.sign") << QString("Math.sign") << QString("sign");
QTest::newRow("Math.sin") << QString("Math.sin") << QString("sin");
QTest::newRow("Math.sqrt") << QString("Math.sqrt") << QString("sqrt");
QTest::newRow("Math.tan") << QString("Math.tan") << QString("tan");
QTest::newRow("Number") << QString("Number") << QString("Number");
QTest::newRow("Number.isFinite") << QString("Number.isFinite") << QString("isFinite");
QTest::newRow("Number.isNaN") << QString("Number.isNaN") << QString("isNaN");
QTest::newRow("Number.prototype.toString") << QString("Number.prototype.toString") << QString("toString");
QTest::newRow("Number.prototype.toLocaleString") << QString("Number.prototype.toLocaleString") << QString("toLocaleString");
QTest::newRow("Number.prototype.valueOf") << QString("Number.prototype.valueOf") << QString("valueOf");
@ -1920,6 +1923,7 @@ void tst_QJSEngine::jsNumberClass()
QVERIFY(ctor.property("NaN").isNumber());
QVERIFY(ctor.property("NEGATIVE_INFINITY").isNumber());
QVERIFY(ctor.property("POSITIVE_INFINITY").isNumber());
QVERIFY(ctor.property("EPSILON").isNumber());
}
QCOMPARE(proto.toNumber(), qreal(0));
QVERIFY(proto.property("constructor").strictlyEquals(ctor));
@ -1958,6 +1962,50 @@ void tst_QJSEngine::jsNumberClass()
QCOMPARE(ret.toNumber(), qreal(456));
}
QVERIFY(ctor.property("isFinite").isCallable());
{
QJSValue ret = eng.evaluate("Number.isFinite()");
QVERIFY(ret.isBool());
QCOMPARE(ret.toBool(), false);
}
{
QJSValue ret = eng.evaluate("Number.isFinite(NaN)");
QVERIFY(ret.isBool());
QCOMPARE(ret.toBool(), false);
}
{
QJSValue ret = eng.evaluate("Number.isFinite(Infinity)");
QVERIFY(ret.isBool());
QCOMPARE(ret.toBool(), false);
}
{
QJSValue ret = eng.evaluate("Number.isFinite(-Infinity)");
QVERIFY(ret.isBool());
QCOMPARE(ret.toBool(), false);
}
{
QJSValue ret = eng.evaluate("Number.isFinite(123)");
QVERIFY(ret.isBool());
QCOMPARE(ret.toBool(), true);
}
QVERIFY(ctor.property("isNaN").isCallable());
{
QJSValue ret = eng.evaluate("Number.isNaN()");
QVERIFY(ret.isBool());
QCOMPARE(ret.toBool(), false);
}
{
QJSValue ret = eng.evaluate("Number.isNaN(NaN)");
QVERIFY(ret.isBool());
QCOMPARE(ret.toBool(), true);
}
{
QJSValue ret = eng.evaluate("Number.isNaN(123)");
QVERIFY(ret.isBool());
QCOMPARE(ret.toBool(), false);
}
QVERIFY(proto.property("toString").isCallable());
{
QJSValue ret = eng.evaluate("new Number(123).toString()");