using namespace QQmlJS::VM;
+static const double qt_PI = 2.0 * ::asin(1.0);
+
//
// Object
//
int start = int (ctx->argument(0).toInteger(ctx));
int end = ctx->argument(1).isUndefined()
- ? length : int (ctx->argument(1).toInteger(ctx));
+ ? length : int (ctx->argument(1).toInteger(ctx));
if (start < 0)
start = qMax(length + start, 0);
{
Value self = ctx->thisObject;
assert(self.isObject());
-// if (self.classInfo() != classInfo) {
-// return throwThisObjectTypeError(
-// ctx, QLatin1String("Number.prototype.toString"));
-// }
+ // if (self.classInfo() != classInfo) {
+ // return throwThisObjectTypeError(
+ // ctx, QLatin1String("Number.prototype.toString"));
+ // }
Value arg = ctx->argument(0);
if (!arg.isUndefined()) {
int radix = arg.toInt32(ctx);
-// if (radix < 2 || radix > 36)
-// return ctx->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix")
-// .arg(radix));
+ // if (radix < 2 || radix > 36)
+ // return ctx->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix")
+ // .arg(radix));
if (radix != 10) {
Value internalValue;
self.objectValue->defaultValue(ctx, &internalValue, NUMBER_HINT);
{
Value self = ctx->thisObject;
assert(self.isObject());
-// if (self.classInfo() != classInfo) {
-// return throwThisObjectTypeError(
-// context, QLatin1String("Number.prototype.toLocaleString"));
-// }
+ // if (self.classInfo() != classInfo) {
+ // return throwThisObjectTypeError(
+ // context, QLatin1String("Number.prototype.toLocaleString"));
+ // }
Value internalValue;
self.objectValue->defaultValue(ctx, &internalValue, STRING_HINT);
String *str = internalValue.toString(ctx);
{
Value self = ctx->thisObject;
assert(self.isObject());
-// if (self.classInfo() != classInfo) {
-// return throwThisObjectTypeError(
-// context, QLatin1String("Number.prototype.toLocaleString"));
-// }
+ // if (self.classInfo() != classInfo) {
+ // return throwThisObjectTypeError(
+ // context, QLatin1String("Number.prototype.toLocaleString"));
+ // }
Value internalValue;
self.objectValue->defaultValue(ctx, &internalValue, NUMBER_HINT);
ctx->result = internalValue;
{
Value self = ctx->thisObject;
assert(self.isObject());
-// if (self.classInfo() != classInfo) {
-// return throwThisObjectTypeError(
-// ctx, QLatin1String("Number.prototype.toFixed"));
-// }
+ // if (self.classInfo() != classInfo) {
+ // return throwThisObjectTypeError(
+ // ctx, QLatin1String("Number.prototype.toFixed"));
+ // }
double fdigits = 0;
if (ctx->argumentCount > 0)
{
Value self = ctx->thisObject;
assert(self.isObject());
-// if (self.classInfo() != classInfo) {
-// return throwThisObjectTypeError(
-// ctx, QLatin1String("Number.prototype.toFixed"));
-// }
+ // if (self.classInfo() != classInfo) {
+ // return throwThisObjectTypeError(
+ // ctx, QLatin1String("Number.prototype.toFixed"));
+ // }
double fdigits = 0;
if (ctx->argumentCount > 0)
{
Value self = ctx->thisObject;
assert(self.isObject());
-// if (self.classInfo() != classInfo) {
-// return throwThisObjectTypeError(
-// ctx, QLatin1String("Number.prototype.toFixed"));
-// }
+ // if (self.classInfo() != classInfo) {
+ // return throwThisObjectTypeError(
+ // ctx, QLatin1String("Number.prototype.toFixed"));
+ // }
double fdigits = 0;
if (ctx->argumentCount > 0)
double v = internalValue.toNumber(ctx);
ctx->result = Value::string(ctx, QString::number(v, 'g', int (fdigits)));
}
+
+//
+// Math object
+//
+MathObject::MathObject(Context *ctx)
+{
+ setProperty(ctx, QLatin1String("E"), Value::number(ctx, ::exp(1.0)));
+ setProperty(ctx, QLatin1String("LN2"), Value::number(ctx, ::log(2.0)));
+ setProperty(ctx, QLatin1String("LN10"), Value::number(ctx, ::log(10.0)));
+ setProperty(ctx, QLatin1String("LOG2E"), Value::number(ctx, 1.0/::log(2.0)));
+ setProperty(ctx, QLatin1String("LOG10E"), Value::number(ctx, 1.0/::log(10.0)));
+ setProperty(ctx, QLatin1String("PI"), Value::number(ctx, qt_PI));
+ setProperty(ctx, QLatin1String("SQRT1_2"), Value::number(ctx, ::sqrt(0.5)));
+ setProperty(ctx, QLatin1String("SQRT2"), Value::number(ctx, ::sqrt(2.0)));
+
+ setProperty(ctx, QLatin1String("abs"), method_abs, 1);
+ setProperty(ctx, QLatin1String("acos"), method_acos, 1);
+ setProperty(ctx, QLatin1String("asin"), method_asin, 0);
+ setProperty(ctx, QLatin1String("atan"), method_atan, 1);
+ setProperty(ctx, QLatin1String("atan2"), method_atan2, 2);
+ setProperty(ctx, QLatin1String("ceil"), method_ceil, 1);
+ setProperty(ctx, QLatin1String("cos"), method_cos, 1);
+ setProperty(ctx, QLatin1String("exp"), method_exp, 1);
+ setProperty(ctx, QLatin1String("floor"), method_floor, 1);
+ setProperty(ctx, QLatin1String("log"), method_log, 1);
+ setProperty(ctx, QLatin1String("max"), method_max, 2);
+ setProperty(ctx, QLatin1String("min"), method_min, 2);
+ setProperty(ctx, QLatin1String("pow"), method_pow, 2);
+ setProperty(ctx, QLatin1String("random"), method_random, 0);
+ setProperty(ctx, QLatin1String("round"), method_round, 1);
+ setProperty(ctx, QLatin1String("sin"), method_sin, 1);
+ setProperty(ctx, QLatin1String("sqrt"), method_sqrt, 1);
+ setProperty(ctx, QLatin1String("tan"), method_tan, 1);
+}
+
+/* copies the sign from y to x and returns the result */
+static double copySign(double x, double y)
+{
+ uchar *xch = (uchar *)&x;
+ uchar *ych = (uchar *)&y;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ xch[0] = (xch[0] & 0x7f) | (ych[0] & 0x80);
+ else
+ xch[7] = (xch[7] & 0x7f) | (ych[7] & 0x80);
+ return x;
+}
+
+void MathObject::method_abs(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ if (v == 0) // 0 | -0
+ ctx->result = Value::number(ctx, 0);
+ else
+ ctx->result = Value::number(ctx, v < 0 ? -v : v);
+}
+
+void MathObject::method_acos(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ if (v > 1)
+ ctx->result = Value::number(ctx, qSNaN());
+ else
+ ctx->result = Value::number(ctx, ::acos(v));
+}
+
+void MathObject::method_asin(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ if (v > 1)
+ ctx->result = Value::number(ctx, qSNaN());
+ else
+ ctx->result = Value::number(ctx, ::asin(v));
+}
+
+void MathObject::method_atan(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ if (v == 0.0)
+ ctx->result = Value::number(ctx, v);
+ else
+ ctx->result = Value::number(ctx, ::atan(v));
+}
+
+void MathObject::method_atan2(Context *ctx)
+{
+ double v1 = ctx->argument(0).toNumber(ctx);
+ double v2 = ctx->argument(1).toNumber(ctx);
+ if ((v1 < 0) && qIsFinite(v1) && qIsInf(v2) && (copySign(1.0, v2) == 1.0)) {
+ ctx->result = Value::number(ctx, copySign(0, -1.0));
+ return;
+ }
+ if ((v1 == 0.0) && (v2 == 0.0)) {
+ if ((copySign(1.0, v1) == 1.0) && (copySign(1.0, v2) == -1.0)) {
+ ctx->result = Value::number(ctx, qt_PI);
+ return;
+ } else if ((copySign(1.0, v1) == -1.0) && (copySign(1.0, v2) == -1.0)) {
+ ctx->result = Value::number(ctx, -qt_PI);
+ return;
+ }
+ }
+ ctx->result = Value::number(ctx, ::atan2(v1, v2));
+}
+
+void MathObject::method_ceil(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ if (v < 0.0 && v > -1.0)
+ ctx->result = Value::number(ctx, copySign(0, -1.0));
+ else
+ ctx->result = Value::number(ctx, ::ceil(v));
+}
+
+void MathObject::method_cos(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ ctx->result = Value::number(ctx, ::cos(v));
+}
+
+void MathObject::method_exp(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ if (qIsInf(v)) {
+ if (copySign(1.0, v) == -1.0)
+ ctx->result = Value::number(ctx, 0);
+ else
+ ctx->result = Value::number(ctx, qInf());
+ } else {
+ ctx->result = Value::number(ctx, ::exp(v));
+ }
+}
+
+void MathObject::method_floor(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ ctx->result = Value::number(ctx, ::floor(v));
+}
+
+void MathObject::method_log(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ if (v < 0)
+ ctx->result = Value::number(ctx, qSNaN());
+ else
+ ctx->result = Value::number(ctx, ::log(v));
+}
+
+void MathObject::method_max(Context *ctx)
+{
+ double mx = -qInf();
+ for (unsigned i = 0; i < ctx->argumentCount; ++i) {
+ double x = ctx->argument(i).toNumber(ctx);
+ if (x > mx || qIsNaN(x))
+ mx = x;
+ }
+ ctx->result = Value::number(ctx, mx);
+}
+
+void MathObject::method_min(Context *ctx)
+{
+ double mx = qInf();
+ for (unsigned i = 0; i < ctx->argumentCount; ++i) {
+ double x = ctx->argument(i).toNumber(ctx);
+ if ((x == 0 && mx == x && copySign(1.0, x) == -1.0)
+ || (x < mx) || qIsNaN(x)) {
+ mx = x;
+ }
+ }
+ ctx->result = Value::number(ctx, mx);
+}
+
+void MathObject::method_pow(Context *ctx)
+{
+ double x = ctx->argument(0).toNumber(ctx);
+ double y = ctx->argument(1).toNumber(ctx);
+
+ if (qIsNaN(y)) {
+ ctx->result = Value::number(ctx, qSNaN());
+ return;
+ }
+
+ if (y == 0) {
+ ctx->result = Value::number(ctx, 1);
+ } else if (((x == 1) || (x == -1)) && qIsInf(y)) {
+ ctx->result = Value::number(ctx, qSNaN());
+ } else if (((x == 0) && copySign(1.0, x) == 1.0) && (y < 0)) {
+ ctx->result = Value::number(ctx, qInf());
+ } else if ((x == 0) && copySign(1.0, x) == -1.0) {
+ if (y < 0) {
+ if (::fmod(-y, 2.0) == 1.0)
+ ctx->result = Value::number(ctx, -qInf());
+ else
+ ctx->result = Value::number(ctx, qInf());
+ } else if (y > 0) {
+ if (::fmod(y, 2.0) == 1.0)
+ ctx->result = Value::number(ctx, copySign(0, -1.0));
+ else
+ ctx->result = Value::number(ctx, 0);
+ }
+ }
+
+#ifdef Q_OS_AIX
+ else if (qIsInf(x) && copySign(1.0, x) == -1.0) {
+ if (y > 0) {
+ if (::fmod(y, 2.0) == 1.0)
+ ctx->result = Value::number(ctx, -qInf());
+ else
+ ctx->result = Value::number(ctx, qInf());
+ } else if (y < 0) {
+ if (::fmod(-y, 2.0) == 1.0)
+ ctx->result = Value::number(ctx, copySign(0, -1.0));
+ else
+ ctx->result = Value::number(ctx, 0);
+ }
+ }
+#endif
+ else {
+ ctx->result = Value::number(ctx, ::pow(x, y));
+ }
+}
+
+void MathObject::method_random(Context *ctx)
+{
+ ctx->result = Value::number(ctx, qrand() / (double) RAND_MAX);
+}
+
+void MathObject::method_round(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ v = copySign(::floor(v + 0.5), v);
+ ctx->result = Value::number(ctx, v);
+}
+
+void MathObject::method_sin(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ ctx->result = Value::number(ctx, ::sin(v));
+}
+
+void MathObject::method_sqrt(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ ctx->result = Value::number(ctx, ::sqrt(v));
+}
+
+void MathObject::method_tan(Context *ctx)
+{
+ double v = ctx->argument(0).toNumber(ctx);
+ if (v == 0.0)
+ ctx->result = Value::number(ctx, v);
+ else
+ ctx->result = Value::number(ctx, ::tan(v));
+}