Browse Source

change semantics of non-strict compare operator for buffers and pointers

pull/1/head
Sami Vaarala 11 years ago
parent
commit
43e407aa2d
  1. 90
      src/duk_js_ops.c

90
src/duk_js_ops.c

@ -430,9 +430,10 @@ int duk_js_equals_number(double x, double y) {
return 0; return 0;
} }
/* E5 Section 11.9.3 */ /* E5 Section 11.9.3. */
int duk_js_equals(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) { int duk_js_equals(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
duk_context *ctx = (duk_context *) thr; duk_context *ctx = (duk_context *) thr;
duk_tval *tv_tmp;
/* /*
* FIXME: very direct translation now - should be made more * FIXME: very direct translation now - should be made more
@ -442,8 +443,8 @@ int duk_js_equals(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
/* /*
* Same type? * Same type?
* *
* Note: since number values have no explicit tag, need the awkward * Note: since number values have no explicit tag in the 8-byte
* if + switch. * representation, need the awkward if + switch.
*/ */
if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) { if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
@ -500,6 +501,9 @@ int duk_js_equals(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
/* /*
* Types are different; various cases * Types are different; various cases
*
* Since comparison is symmetric, we use a "swap trick" to reduce
* code size.
*/ */
/* undefined/null are considered equal (e.g. "null == undefined" -> true) */ /* undefined/null are considered equal (e.g. "null == undefined" -> true) */
@ -508,38 +512,57 @@ int duk_js_equals(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
return 1; return 1;
} }
/* number/string -> coerce string to number (e.g. "'1.5' == 1.5" -> true) */ /* number/string-or-buffer -> coerce string to number (e.g. "'1.5' == 1.5" -> true) */
if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_STRING(tv_y)) { if (DUK_TVAL_IS_NUMBER(tv_x) && (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
/* FIXME: this is possible without resorting to the value stack */ /* the next 'if' is guaranteed to match after swap */
double d1, d2; tv_tmp = tv_x;
d1 = DUK_TVAL_GET_NUMBER(tv_x); tv_x = tv_y;
duk_push_tval(ctx, tv_y); tv_y = tv_tmp;
duk_to_number(ctx, -1);
d2 = duk_require_number(ctx, -1);
duk_pop(ctx);
return duk_js_equals_number(d1, d2);
} }
if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) { if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) && DUK_TVAL_IS_NUMBER(tv_y)) {
/* FIXME: this is possible without resorting to the value stack */ /* FIXME: this is possible without resorting to the value stack */
double d1, d2; double d1, d2;
d2 = DUK_TVAL_GET_NUMBER(tv_y); d2 = DUK_TVAL_GET_NUMBER(tv_y);
duk_push_tval(ctx, tv_x); duk_push_tval(ctx, tv_x);
duk_to_string(ctx, -1); /* buffer values are coerced first to string here */
duk_to_number(ctx, -1); duk_to_number(ctx, -1);
d1 = duk_require_number(ctx, -1); d1 = duk_require_number(ctx, -1);
duk_pop(ctx); duk_pop(ctx);
return duk_js_equals_number(d1, d2); return duk_js_equals_number(d1, d2);
} }
/* buffer/string -> compare contents */
if (DUK_TVAL_IS_BUFFER(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
tv_tmp = tv_x;
tv_x = tv_y;
tv_y = tv_tmp;
}
if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_BUFFER(tv_y)) {
duk_hstring *h_x = DUK_TVAL_GET_STRING(tv_x);
duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
size_t len_x = DUK_HSTRING_GET_BYTELEN(h_x);
size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
void *buf_x;
void *buf_y;
if (len_x != len_y) {
return 0;
}
buf_x = (void *) DUK_HSTRING_GET_DATA(h_x);
buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(h_y);
/* if len_x == len_y == 0, buf_x and/or buf_y may
* be NULL, but that's OK.
*/
DUK_ASSERT(len_x == len_y);
DUK_ASSERT(len_x == 0 || buf_x != NULL);
DUK_ASSERT(len_y == 0 || buf_y != NULL);
return (DUK_MEMCMP(buf_x, buf_y, len_x) == 0) ? 1 : 0;
}
/* boolean/any -> coerce boolean to number and try again */ /* boolean/any -> coerce boolean to number and try again */
if (DUK_TVAL_IS_BOOLEAN(tv_x)) { if (DUK_TVAL_IS_BOOLEAN(tv_x)) {
/* ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1. */ tv_tmp = tv_x;
int rc; tv_x = tv_y;
DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_x) == 0 || DUK_TVAL_GET_BOOLEAN(tv_x) == 1); tv_y = tv_tmp;
duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_x));
duk_push_tval(ctx, tv_y);
rc = duk_js_equals(thr, duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
duk_pop_2(ctx);
return rc;
} }
if (DUK_TVAL_IS_BOOLEAN(tv_y)) { if (DUK_TVAL_IS_BOOLEAN(tv_y)) {
/* ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1. */ /* ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1. */
@ -552,19 +575,15 @@ int duk_js_equals(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
return rc; return rc;
} }
/* string-or-number/object -> coerce object to primitive (apparently without hint), then try again */ /* string-number-buffer/object -> coerce object to primitive (apparently without hint), then try again */
if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_NUMBER(tv_x)) && if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_NUMBER(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) &&
DUK_TVAL_IS_OBJECT(tv_y)) { DUK_TVAL_IS_OBJECT(tv_y)) {
int rc; tv_tmp = tv_x;
duk_push_tval(ctx, tv_x); tv_x = tv_y;
duk_push_tval(ctx, tv_y); tv_y = tv_tmp;
duk_to_primitive(ctx, -1, DUK_HINT_NONE); /* apparently no hint? */
rc = duk_js_equals(thr, duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
duk_pop_2(ctx);
return rc;
} }
if (DUK_TVAL_IS_OBJECT(tv_x) && if (DUK_TVAL_IS_OBJECT(tv_x) &&
(DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_NUMBER(tv_y))) { (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_NUMBER(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
int rc; int rc;
duk_push_tval(ctx, tv_x); duk_push_tval(ctx, tv_x);
duk_push_tval(ctx, tv_y); duk_push_tval(ctx, tv_y);
@ -574,9 +593,6 @@ int duk_js_equals(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
return rc; return rc;
} }
/* FIXME: object vs. buffer: coerce object to primitive and retry? */
/* FIXME: string vs. buffer: compare contents? */
/* nothing worked -> not equal */ /* nothing worked -> not equal */
return 0; return 0;
} }
@ -1148,7 +1164,7 @@ duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
} }
case DUK_TAG_POINTER: { case DUK_TAG_POINTER: {
/* implementation specific */ /* implementation specific */
idx = DUK_STRIDX_POINTER; idx = DUK_STRIDX_LC_POINTER;
break; break;
} }
case DUK_TAG_STRING: { case DUK_TAG_STRING: {
@ -1167,7 +1183,7 @@ duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
} }
case DUK_TAG_BUFFER: { case DUK_TAG_BUFFER: {
/* implementation specific */ /* implementation specific */
idx = DUK_STRIDX_BUFFER; idx = DUK_STRIDX_LC_BUFFER;
break; break;
} }
default: { default: {

Loading…
Cancel
Save