comparing anything but two numbers or two strings is an error
This commit is contained in:
148
source/quickjs.c
148
source/quickjs.c
@@ -13452,131 +13452,59 @@ static int js_compare_bigint(JSContext *ctx, OPCodeEnum op,
|
||||
static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
|
||||
OPCodeEnum op)
|
||||
{
|
||||
JSValue op1, op2;
|
||||
JSValue op1 = sp[-2], op2 = sp[-1];
|
||||
uint32_t tag1 = JS_VALUE_GET_NORM_TAG(op1);
|
||||
uint32_t tag2 = JS_VALUE_GET_NORM_TAG(op2);
|
||||
int res;
|
||||
uint32_t tag1, tag2;
|
||||
|
||||
op1 = sp[-2];
|
||||
op2 = sp[-1];
|
||||
tag1 = JS_VALUE_GET_NORM_TAG(op1);
|
||||
tag2 = JS_VALUE_GET_NORM_TAG(op2);
|
||||
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
|
||||
if (JS_IsException(op1)) {
|
||||
JS_FreeValue(ctx, op2);
|
||||
goto exception;
|
||||
}
|
||||
op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
|
||||
if (JS_IsException(op2)) {
|
||||
JS_FreeValue(ctx, op1);
|
||||
goto exception;
|
||||
}
|
||||
tag1 = JS_VALUE_GET_NORM_TAG(op1);
|
||||
tag2 = JS_VALUE_GET_NORM_TAG(op2);
|
||||
|
||||
/* string <=> string */
|
||||
if (tag_is_string(tag1) && tag_is_string(tag2)) {
|
||||
if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
|
||||
res = js_string_compare(ctx, JS_VALUE_GET_STRING(op1),
|
||||
if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING)
|
||||
res = js_string_compare(ctx,
|
||||
JS_VALUE_GET_STRING(op1),
|
||||
JS_VALUE_GET_STRING(op2));
|
||||
} else {
|
||||
else
|
||||
res = js_string_rope_compare(ctx, op1, op2, FALSE);
|
||||
}
|
||||
|
||||
switch(op) {
|
||||
case OP_lt:
|
||||
res = (res < 0);
|
||||
break;
|
||||
case OP_lte:
|
||||
res = (res <= 0);
|
||||
break;
|
||||
case OP_gt:
|
||||
res = (res > 0);
|
||||
break;
|
||||
default:
|
||||
case OP_gte:
|
||||
res = (res >= 0);
|
||||
break;
|
||||
case OP_lt: res = (res < 0); break;
|
||||
case OP_lte: res = (res <= 0); break;
|
||||
case OP_gt: res = (res > 0); break;
|
||||
default: res = (res >= 0); break;
|
||||
}
|
||||
JS_FreeValue(ctx, op1);
|
||||
JS_FreeValue(ctx, op2);
|
||||
} else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&
|
||||
(tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {
|
||||
/* fast path for float64/int */
|
||||
goto float64_compare;
|
||||
|
||||
/* number <=> number */
|
||||
} else if ((tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64) &&
|
||||
(tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) {
|
||||
double d1 = (tag1 == JS_TAG_FLOAT64
|
||||
? JS_VALUE_GET_FLOAT64(op1)
|
||||
: (double)JS_VALUE_GET_INT(op1));
|
||||
double d2 = (tag2 == JS_TAG_FLOAT64
|
||||
? JS_VALUE_GET_FLOAT64(op2)
|
||||
: (double)JS_VALUE_GET_INT(op2));
|
||||
|
||||
switch(op) {
|
||||
case OP_lt: res = (d1 < d2); break;
|
||||
case OP_lte: res = (d1 <= d2); break;
|
||||
case OP_gt: res = (d1 > d2); break;
|
||||
default: res = (d1 >= d2); break;
|
||||
}
|
||||
|
||||
/* anything else → TypeError */
|
||||
} else {
|
||||
if ((((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
|
||||
tag_is_string(tag2)) ||
|
||||
((tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) &&
|
||||
tag_is_string(tag1)))) {
|
||||
if (tag_is_string(tag1)) {
|
||||
op1 = JS_StringToBigInt(ctx, op1);
|
||||
if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&
|
||||
JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)
|
||||
goto invalid_bigint_string;
|
||||
}
|
||||
if (tag_is_string(tag2)) {
|
||||
op2 = JS_StringToBigInt(ctx, op2);
|
||||
if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&
|
||||
JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT) {
|
||||
invalid_bigint_string:
|
||||
JS_ThrowTypeError(ctx,
|
||||
"Relational operators only supported on two strings or two numbers");
|
||||
JS_FreeValue(ctx, op1);
|
||||
JS_FreeValue(ctx, op2);
|
||||
res = FALSE;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
op1 = JS_ToNumericFree(ctx, op1);
|
||||
if (JS_IsException(op1)) {
|
||||
JS_FreeValue(ctx, op2);
|
||||
goto exception;
|
||||
}
|
||||
op2 = JS_ToNumericFree(ctx, op2);
|
||||
if (JS_IsException(op2)) {
|
||||
|
||||
/* free the two input values and push the result */
|
||||
JS_FreeValue(ctx, op1);
|
||||
goto exception;
|
||||
}
|
||||
}
|
||||
|
||||
tag1 = JS_VALUE_GET_NORM_TAG(op1);
|
||||
tag2 = JS_VALUE_GET_NORM_TAG(op2);
|
||||
|
||||
if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||
|
||||
tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {
|
||||
res = js_compare_bigint(ctx, op, op1, op2);
|
||||
} else {
|
||||
double d1, d2;
|
||||
|
||||
float64_compare:
|
||||
/* can use floating point comparison */
|
||||
if (tag1 == JS_TAG_FLOAT64) {
|
||||
d1 = JS_VALUE_GET_FLOAT64(op1);
|
||||
} else {
|
||||
d1 = JS_VALUE_GET_INT(op1);
|
||||
}
|
||||
if (tag2 == JS_TAG_FLOAT64) {
|
||||
d2 = JS_VALUE_GET_FLOAT64(op2);
|
||||
} else {
|
||||
d2 = JS_VALUE_GET_INT(op2);
|
||||
}
|
||||
switch(op) {
|
||||
case OP_lt:
|
||||
res = (d1 < d2); /* if NaN return false */
|
||||
break;
|
||||
case OP_lte:
|
||||
res = (d1 <= d2); /* if NaN return false */
|
||||
break;
|
||||
case OP_gt:
|
||||
res = (d1 > d2); /* if NaN return false */
|
||||
break;
|
||||
default:
|
||||
case OP_gte:
|
||||
res = (d1 >= d2); /* if NaN return false */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
JS_FreeValue(ctx, op2);
|
||||
sp[-2] = JS_NewBool(ctx, res);
|
||||
return 0;
|
||||
|
||||
exception:
|
||||
sp[-2] = JS_UNDEFINED;
|
||||
sp[-1] = JS_UNDEFINED;
|
||||
|
||||
Reference in New Issue
Block a user