diff --git a/dlls/jscript/date.c b/dlls/jscript/date.c index 3a681b9be6..642c9ec415 100644 --- a/dlls/jscript/date.c +++ b/dlls/jscript/date.c @@ -2634,7 +2634,7 @@ static HRESULT DateConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPP case 1: { VARIANT prim, num; - hres = to_primitive(dispex->ctx, get_arg(dp,0), ei, &prim); + hres = to_primitive(dispex->ctx, get_arg(dp,0), ei, &prim, NO_HINT); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index a387ecdbff..01f4d49f42 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -828,7 +828,7 @@ HRESULT jsdisp_call_value(DispatchEx *disp, LCID lcid, WORD flags, DISPPARAMS *d return disp->builtin_info->value_prop.invoke(disp, lcid, flags, dp, retv, ei, caller); } -static HRESULT jsdisp_call(DispatchEx *disp, DISPID id, LCID lcid, WORD flags, DISPPARAMS *dp, VARIANT *retv, +HRESULT jsdisp_call(DispatchEx *disp, DISPID id, LCID lcid, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) { dispex_prop_t *prop; diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 05c6225daa..00eb087809 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -1931,11 +1931,11 @@ static HRESULT add_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexcept_ VARIANT r, l; HRESULT hres; - hres = to_primitive(ctx->parser->script, lval, ei, &l); + hres = to_primitive(ctx->parser->script, lval, ei, &l, NO_HINT); if(FAILED(hres)) return hres; - hres = to_primitive(ctx->parser->script, rval, ei, &r); + hres = to_primitive(ctx->parser->script, rval, ei, &r, NO_HINT); if(FAILED(hres)) { VariantClear(&l); return hres; @@ -2518,7 +2518,7 @@ static HRESULT equal_values(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexc VARIANT v; HRESULT hres; - hres = to_primitive(ctx->parser->script, rval, ei, &v); + hres = to_primitive(ctx->parser->script, rval, ei, &v, NO_HINT); if(FAILED(hres)) return hres; @@ -2533,7 +2533,7 @@ static HRESULT equal_values(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, jsexc VARIANT v; HRESULT hres; - hres = to_primitive(ctx->parser->script, lval, ei, &v); + hres = to_primitive(ctx->parser->script, lval, ei, &v, NO_HINT); if(FAILED(hres)) return hres; @@ -2638,11 +2638,11 @@ static HRESULT less_eval(exec_ctx_t *ctx, VARIANT *lval, VARIANT *rval, BOOL gre VARIANT l, r, ln, rn; HRESULT hres; - hres = to_primitive(ctx->parser->script, lval, ei, &l); + hres = to_primitive(ctx->parser->script, lval, ei, &l, NO_HINT); if(FAILED(hres)) return hres; - hres = to_primitive(ctx->parser->script, rval, ei, &r); + hres = to_primitive(ctx->parser->script, rval, ei, &r, NO_HINT); if(FAILED(hres)) { VariantClear(&l); return hres; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 7a4158c631..8d7d61f101 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -123,6 +123,7 @@ DispatchEx *iface_to_jsdisp(IUnknown*); HRESULT disp_call(IDispatch*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*); HRESULT jsdisp_call_value(DispatchEx*,LCID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*); +HRESULT jsdisp_call(DispatchEx*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*); HRESULT disp_propget(IDispatch*,DISPID,LCID,VARIANT*,jsexcept_t*,IServiceProvider*); HRESULT disp_propput(IDispatch*,DISPID,LCID,VARIANT*,jsexcept_t*,IServiceProvider*); HRESULT jsdisp_propget(DispatchEx*,DISPID,LCID,VARIANT*,jsexcept_t*,IServiceProvider*); @@ -145,7 +146,13 @@ HRESULT create_string(script_ctx_t*,const WCHAR*,DWORD,DispatchEx**); HRESULT create_bool(script_ctx_t*,VARIANT_BOOL,DispatchEx**); HRESULT create_number(script_ctx_t*,VARIANT*,DispatchEx**); -HRESULT to_primitive(script_ctx_t*,VARIANT*,jsexcept_t*,VARIANT*); +typedef enum { + NO_HINT, + HINT_STRING, + HINT_NUMBER +} hint_t; + +HRESULT to_primitive(script_ctx_t*,VARIANT*,jsexcept_t*,VARIANT*, hint_t); HRESULT to_boolean(VARIANT*,VARIANT_BOOL*); HRESULT to_number(script_ctx_t*,VARIANT*,jsexcept_t*,VARIANT*); HRESULT to_integer(script_ctx_t*,VARIANT*,jsexcept_t*,VARIANT*); diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c index eab850bfe3..4a885a50b7 100644 --- a/dlls/jscript/jsutils.c +++ b/dlls/jscript/jsutils.c @@ -175,7 +175,7 @@ jsheap_t *jsheap_mark(jsheap_t *heap) } /* ECMA-262 3rd Edition 9.1 */ -HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret) +HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret, hint_t hint) { switch(V_VT(v)) { case VT_EMPTY: @@ -189,8 +189,61 @@ HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret V_VT(ret) = VT_BSTR; V_BSTR(ret) = SysAllocString(V_BSTR(v)); break; - case VT_DISPATCH: - return disp_propget(V_DISPATCH(v), DISPID_VALUE, ctx->lcid, ret, ei, NULL /*FIXME*/); + case VT_DISPATCH: { + DispatchEx *jsdisp; + DISPID id; + DISPPARAMS dp = {NULL, NULL, 0, 0}; + HRESULT hres; + + static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; + static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0}; + + jsdisp = iface_to_jsdisp((IUnknown*)V_DISPATCH(v)); + if(!jsdisp) + return disp_propget(V_DISPATCH(v), DISPID_VALUE, ctx->lcid, ret, ei, NULL /*FIXME*/); + + if(hint == NO_HINT) + hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER; + + /* Native implementation doesn't throw TypeErrors, returns strange values */ + + hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id); + if(SUCCEEDED(hres)) { + hres = jsdisp_call(jsdisp, id, ctx->lcid, DISPATCH_METHOD, &dp, ret, ei, NULL /*FIXME*/); + if(FAILED(hres)) { + FIXME("throw TypeError\n"); + jsdisp_release(jsdisp); + return hres; + } + else if(V_VT(ret) != VT_DISPATCH) { + jsdisp_release(jsdisp); + return S_OK; + } + else + IDispatch_Release(V_DISPATCH(ret)); + } + + hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id); + if(SUCCEEDED(hres)) { + hres = jsdisp_call(jsdisp, id, ctx->lcid, DISPATCH_METHOD, &dp, ret, ei, NULL /*FIXME*/); + if(FAILED(hres)) { + FIXME("throw TypeError\n"); + jsdisp_release(jsdisp); + return hres; + } + else if(V_VT(ret) != VT_DISPATCH) { + jsdisp_release(jsdisp); + return S_OK; + } + else + IDispatch_Release(V_DISPATCH(ret)); + } + + jsdisp_release(jsdisp); + + FIXME("throw TypeError\n"); + return E_FAIL; + } default: FIXME("Unimplemented for vt %d\n", V_VT(v)); return E_NOTIMPL; @@ -356,7 +409,7 @@ HRESULT to_number(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret) VARIANT prim; HRESULT hres; - hres = to_primitive(ctx, v, ei, &prim); + hres = to_primitive(ctx, v, ei, &prim, HINT_NUMBER); if(FAILED(hres)) return hres; @@ -489,7 +542,7 @@ HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str) VARIANT prim; HRESULT hres; - hres = to_primitive(ctx, v, ei, &prim); + hres = to_primitive(ctx, v, ei, &prim, HINT_STRING); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 7075aecbfa..79b255b33c 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -1026,6 +1026,8 @@ date.setUTCMonth(22, 37); ok(date.getTime() === 60987050010, "date.getTime() = " + date.getTime()); date.setUTCFullYear(83, 21, 321); ok(date.getTime() === -59464984149990, "date.getTime() = " + date.getTime()); +ok(Math.abs(date) === 59464984149990, "Math.abs(date) = " + Math.abs(date)); +ok(getVT(date+1) === "VT_BSTR", "getVT(date+1) = " + getVT(date+1)); ok(isNaN(Date.parse()), "Date.parse() is not NaN"); ok(isNaN(Date.parse("")), "Date.parse(\"\") is not NaN"); diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js index cf04f9e0bb..fcd6ec3d5c 100644 --- a/dlls/jscript/tests/lang.js +++ b/dlls/jscript/tests/lang.js @@ -882,4 +882,16 @@ function testEmbededFunctions() { testEmbededFunctions(); +date = new Date(); +date.toString = function() { return "toString"; } +ok(""+date === "toString", "''+date = " + date); +date.toString = function() { return this; } +ok(""+date === ""+date.valueOf(), "''+date = " + date); + +str = new String("test"); +str.valueOf = function() { return "valueOf"; } +ok(""+str === "valueOf", "''+str = " + str); +str.valueOf = function() { return new Date(); } +ok(""+str === "test", "''+str = " + str); + reportSuccess();