DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) { duk_double_union du; du.d = x; /* Assumes we're dealing with a Duktape internal NaN which is * NaN normalized if duk_tval requires it. */ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du); }
DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) { duk_context *ctx = (duk_hthread *) thr; DUK_ASSERT(thr != NULL); DUK_ASSERT(tv != NULL); switch (DUK_TVAL_GET_TAG(tv)) { case DUK_TAG_UNDEFINED: { /* return a specific NaN (although not strictly necessary) */ duk_double_union du; DUK_DBLUNION_SET_NAN(&du); DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); return du.d; } case DUK_TAG_NULL: { /* +0.0 */ return 0.0; } case DUK_TAG_BOOLEAN: { if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) { return 1.0; } return 0.0; } case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); duk_push_hstring(ctx, h); return duk__tonumber_string_raw(thr); } case DUK_TAG_OBJECT: { /* Note: ToPrimitive(object,hint) == [[DefaultValue]](object,hint), * so use [[DefaultValue]] directly. */ duk_double_t d; duk_push_tval(ctx, tv); duk_to_defaultvalue(ctx, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */ /* recursive call for a primitive value (guaranteed not to cause second * recursion). */ d = duk_js_tonumber(thr, duk_require_tval(ctx, -1)); duk_pop(ctx); return d; } case DUK_TAG_BUFFER: { /* Coerce like a string. This makes sense because addition also treats * buffers like strings. */ duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); duk_push_hbuffer(ctx, h); duk_to_string(ctx, -1); /* XXX: expensive, but numconv now expects to see a string */ return duk__tonumber_string_raw(thr); } case DUK_TAG_POINTER: { /* Coerce like boolean */ void *p = DUK_TVAL_GET_POINTER(tv); return (p != NULL ? 1.0 : 0.0); } case DUK_TAG_LIGHTFUNC: { /* +(function(){}) -> NaN */ return DUK_DOUBLE_NAN; } #if defined(DUK_USE_FASTINT) case DUK_TAG_FASTINT: return (duk_double_t) DUK_TVAL_GET_FASTINT(tv); #endif default: { /* number */ DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); return DUK_TVAL_GET_DOUBLE(tv); } } DUK_UNREACHABLE(); }