jscript: Add Error_message implementation.
[wine] / dlls / jscript / error.c
1 /*
2  * Copyright 2009 Piotr Caban
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "jscript.h"
20
21 #include "wine/debug.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
24
25 typedef struct {
26     DispatchEx dispex;
27
28     VARIANT message;
29 } ErrorInstance;
30
31 static const WCHAR messageW[] = {'m','e','s','s','a','g','e',0};
32 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
33 static const WCHAR hasOwnPropertyW[] = {'h','a','s','O','w','n','P','r','o','p','e','r','t','y',0};
34 static const WCHAR propertyIsEnumerableW[] =
35     {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
36 static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
37
38 /* ECMA-262 3rd Edition    15.11.4.3 */
39 static HRESULT Error_message(DispatchEx *dispex, LCID lcid, WORD flags,
40         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
41 {
42     ErrorInstance *This = (ErrorInstance*)dispex;
43
44     TRACE("\n");
45
46     switch(flags) {
47     case DISPATCH_PROPERTYGET:
48         return VariantCopy(retv, &This->message);
49     case DISPATCH_PROPERTYPUT:
50         return VariantCopy(&This->message, get_arg(dp, 0));
51     default:
52         FIXME("unimplemented flags %x\n", flags);
53         return E_NOTIMPL;
54     }
55 }
56
57 static HRESULT Error_toString(DispatchEx *dispex, LCID lcid, WORD flags,
58         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
59 {
60     FIXME("\n");
61     return E_NOTIMPL;
62 }
63
64 static HRESULT Error_hasOwnProperty(DispatchEx *dispex, LCID lcid, WORD flags,
65         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
66 {
67     FIXME("\n");
68     return E_NOTIMPL;
69 }
70
71 static HRESULT Error_propertyIsEnumerable(DispatchEx *dispex, LCID lcid, WORD flags,
72         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
73 {
74     FIXME("\n");
75     return E_NOTIMPL;
76 }
77
78
79 static HRESULT Error_isPrototypeOf(DispatchEx *dispex, LCID lcid, WORD flags,
80         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
81 {
82     FIXME("\n");
83     return E_NOTIMPL;
84 }
85
86 static HRESULT Error_value(DispatchEx *dispex, LCID lcid, WORD flags,
87         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
88 {
89     FIXME("\n");
90     return E_NOTIMPL;
91 }
92
93 static void Error_destructor(DispatchEx *dispex)
94 {
95     ErrorInstance *This = (ErrorInstance*)dispex;
96
97     VariantClear(&This->message);
98     heap_free(This);
99 }
100
101 static const builtin_prop_t Error_props[] = {
102     {hasOwnPropertyW,           Error_hasOwnProperty,               PROPF_METHOD},
103     {isPrototypeOfW,            Error_isPrototypeOf,                PROPF_METHOD},
104     {messageW,                  Error_message,                      0},
105     {propertyIsEnumerableW,     Error_propertyIsEnumerable,         PROPF_METHOD},
106     {toStringW,                 Error_toString,                     PROPF_METHOD}
107 };
108
109 static const builtin_info_t Error_info = {
110     JSCLASS_ERROR,
111     {NULL, Error_value, 0},
112     sizeof(Error_props)/sizeof(*Error_props),
113     Error_props,
114     Error_destructor,
115     NULL
116 };
117
118 static const builtin_prop_t ErrorInst_props[] = {
119     {hasOwnPropertyW,           Error_hasOwnProperty,               PROPF_METHOD},
120     {isPrototypeOfW,            Error_isPrototypeOf,                PROPF_METHOD},
121     {messageW,                  Error_message,                      0},
122     {propertyIsEnumerableW,     Error_propertyIsEnumerable,         PROPF_METHOD}
123 };
124
125 static const builtin_info_t ErrorInst_info = {
126     JSCLASS_ERROR,
127     {NULL, Error_value, 0},
128     sizeof(ErrorInst_props)/sizeof(*ErrorInst_props),
129     ErrorInst_props,
130     Error_destructor,
131     NULL
132 };
133
134 static HRESULT alloc_error(script_ctx_t *ctx, BOOL error_prototype,
135         DispatchEx *constr, ErrorInstance **ret)
136 {
137     ErrorInstance *err;
138     DispatchEx *inherit;
139     HRESULT hres;
140
141     err = heap_alloc_zero(sizeof(ErrorInstance));
142     if(!err)
143         return E_OUTOFMEMORY;
144
145     inherit = error_prototype ? ctx->object_constr : ctx->error_constr;
146     hres = init_dispex_from_constr(&err->dispex, ctx,
147             error_prototype ? &Error_info : &ErrorInst_info,
148             constr ? constr : inherit);
149     if(FAILED(hres)) {
150         heap_free(err);
151         return hres;
152     }
153
154     *ret = err;
155     return S_OK;
156 }
157
158 static HRESULT create_error(script_ctx_t *ctx, DispatchEx *constr,
159         const WCHAR *msg, DispatchEx **ret)
160 {
161     ErrorInstance *err;
162     HRESULT hres;
163
164     hres = alloc_error(ctx, FALSE, constr, &err);
165     if(FAILED(hres))
166         return hres;
167
168     V_VT(&err->message) = VT_BSTR;
169     if(msg) V_BSTR(&err->message) = SysAllocString(msg);
170     else V_BSTR(&err->message) = SysAllocStringLen(NULL, 0);
171
172     if(!V_BSTR(&err->message)) {
173         heap_free(err);
174         return E_OUTOFMEMORY;
175     }
176
177     *ret = &err->dispex;
178     return S_OK;
179 }
180
181 static HRESULT error_constr(DispatchEx *dispex, WORD flags, DISPPARAMS *dp,
182         VARIANT *retv, jsexcept_t *ei, DispatchEx *constr) {
183     DispatchEx *err;
184     BSTR msg = NULL;
185     HRESULT hres;
186
187     if(arg_cnt(dp)) {
188         hres = to_string(dispex->ctx, get_arg(dp, 0), ei, &msg);
189         if(FAILED(hres))
190             return hres;
191     }
192
193     switch(flags) {
194     case INVOKE_FUNC:
195     case DISPATCH_CONSTRUCT:
196         hres = create_error(dispex->ctx, constr, msg, &err);
197         if(FAILED(hres))
198             return hres;
199
200         if(retv) {
201             V_VT(retv) = VT_DISPATCH;
202             V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(err);
203         }
204         else
205             IDispatchEx_Release(_IDispatchEx_(err));
206
207         return S_OK;
208
209     default:
210         FIXME("unimplemented flags %x\n", flags);
211         return E_NOTIMPL;
212     }
213 }
214
215 static HRESULT ErrorConstr_value(DispatchEx *dispex, LCID lcid, WORD flags,
216         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
217 {
218     TRACE("\n");
219     return error_constr(dispex, flags, dp, retv, ei,
220             dispex->ctx->error_constr);
221 }
222
223 static HRESULT EvalErrorConstr_value(DispatchEx *dispex, LCID lcid, WORD flags,
224         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
225 {
226     TRACE("\n");
227     return error_constr(dispex, flags, dp, retv, ei,
228             dispex->ctx->eval_error_constr);
229 }
230
231 static HRESULT RangeErrorConstr_value(DispatchEx *dispex, LCID lcid, WORD flags,
232         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
233 {
234     TRACE("\n");
235     return error_constr(dispex, flags, dp, retv, ei,
236             dispex->ctx->range_error_constr);
237 }
238
239 static HRESULT ReferenceErrorConstr_value(DispatchEx *dispex, LCID lcid, WORD flags,
240         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
241 {
242     TRACE("\n");
243     return error_constr(dispex, flags, dp, retv, ei,
244             dispex->ctx->reference_error_constr);
245 }
246
247 static HRESULT SyntaxErrorConstr_value(DispatchEx *dispex, LCID lcid, WORD flags,
248         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
249 {
250     TRACE("\n");
251     return error_constr(dispex, flags, dp, retv, ei,
252             dispex->ctx->syntax_error_constr);
253 }
254
255 static HRESULT TypeErrorConstr_value(DispatchEx *dispex, LCID lcid, WORD flags,
256         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
257 {
258     TRACE("\n");
259     return error_constr(dispex, flags, dp, retv, ei,
260             dispex->ctx->type_error_constr);
261 }
262
263 static HRESULT URIErrorConstr_value(DispatchEx *dispex, LCID lcid, WORD flags,
264         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
265 {
266     TRACE("\n");
267     return error_constr(dispex, flags, dp, retv, ei,
268             dispex->ctx->uri_error_constr);
269 }
270
271 HRESULT init_error_constr(script_ctx_t *ctx)
272 {
273     static const WCHAR nameW[] = {'n','a','m','e',0};
274     static const WCHAR ErrorW[] = {'E','r','r','o','r',0};
275     static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0};
276     static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0};
277     static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0};
278     static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0};
279     static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0};
280     static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0};
281     static const WCHAR *names[] = {ErrorW, EvalErrorW, RangeErrorW,
282         ReferenceErrorW, SyntaxErrorW, TypeErrorW, URIErrorW};
283     DispatchEx **constr_addr[] = {&ctx->error_constr, &ctx->eval_error_constr,
284         &ctx->range_error_constr, &ctx->reference_error_constr,
285         &ctx->syntax_error_constr, &ctx->type_error_constr,
286         &ctx->uri_error_constr};
287     static builtin_invoke_t constr_val[] = {ErrorConstr_value, EvalErrorConstr_value,
288         RangeErrorConstr_value, ReferenceErrorConstr_value, SyntaxErrorConstr_value,
289         TypeErrorConstr_value, URIErrorConstr_value};
290
291     ErrorInstance *err;
292     INT i;
293     VARIANT v;
294     HRESULT hres;
295
296     for(i=0; i<7; i++) {
297         hres = alloc_error(ctx, i==0, NULL, &err);
298         if(FAILED(hres))
299             return hres;
300
301         V_VT(&v) = VT_BSTR;
302         V_BSTR(&v) = SysAllocString(names[i]);
303         if(!V_BSTR(&v)) {
304             IDispatchEx_Release(_IDispatchEx_(&err->dispex));
305             return E_OUTOFMEMORY;
306         }
307
308         hres = jsdisp_propput_name(&err->dispex, nameW, ctx->lcid, &v, NULL/*FIXME*/, NULL/*FIXME*/);
309
310         if(SUCCEEDED(hres))
311             hres = create_builtin_function(ctx, constr_val[i], NULL,
312                     PROPF_CONSTR, &err->dispex, constr_addr[i]);
313
314         IDispatchEx_Release(_IDispatchEx_(&err->dispex));
315         VariantClear(&v);
316         if(FAILED(hres))
317             return hres;
318     }
319
320     return S_OK;
321 }