jscript: Added '>>>=' expression implementation.
[wine] / dlls / jscript / global.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
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 #include "engine.h"
21
22 #include "wine/debug.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
25
26 static const WCHAR NaNW[] = {'N','a','N',0};
27 static const WCHAR InfinityW[] = {'I','n','f','i','n','i','t','y',0};
28 static const WCHAR ArrayW[] = {'A','r','r','a','y',0};
29 static const WCHAR BooleanW[] = {'B','o','o','l','e','a','n',0};
30 static const WCHAR DateW[] = {'D','a','t','e',0};
31 static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0};
32 static const WCHAR NumberW[] = {'N','u','m','b','e','r',0};
33 static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
34 static const WCHAR StringW[] = {'S','t','r','i','n','g',0};
35 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
36 static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0};
37 static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
38 static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0};
39 static const WCHAR escapeW[] = {'e','s','c','a','p','e',0};
40 static const WCHAR evalW[] = {'e','v','a','l',0};
41 static const WCHAR isNaNW[] = {'i','s','N','a','N',0};
42 static const WCHAR isFiniteW[] = {'i','s','F','i','n','i','t','e',0};
43 static const WCHAR parseIntW[] = {'p','a','r','s','e','I','n','t',0};
44 static const WCHAR parseFloatW[] = {'p','a','r','s','e','F','l','o','a','t',0};
45 static const WCHAR unescapeW[] = {'u','n','e','s','c','a','p','e',0};
46 static const WCHAR GetObjectW[] = {'G','e','t','O','b','j','e','c','t',0};
47 static const WCHAR ScriptEngineW[] = {'S','c','r','i','p','t','E','n','g','i','n','e',0};
48 static const WCHAR ScriptEngineMajorVersionW[] =
49     {'S','c','r','i','p','t','E','n','g','i','n','e','M','a','j','o','r','V','e','r','s','i','o','n',0};
50 static const WCHAR ScriptEngineMinorVersionW[] =
51     {'S','c','r','i','p','t','E','n','g','i','n','e','M','i','n','o','r','V','e','r','s','i','o','n',0};
52 static const WCHAR ScriptEngineBuildVersionW[] =
53     {'S','c','r','i','p','t','E','n','g','i','n','e','B','u','i','l','d','V','e','r','s','i','o','n',0};
54 static const WCHAR CollectGarbageW[] = {'C','o','l','l','e','c','t','G','a','r','b','a','g','e',0};
55 static const WCHAR MathW[] = {'M','a','t','h',0};
56
57 static HRESULT constructor_call(DispatchEx *constr, LCID lcid, WORD flags, DISPPARAMS *dp,
58         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
59 {
60     if(flags != DISPATCH_PROPERTYGET)
61         return jsdisp_call_value(constr, lcid, flags, dp, retv, ei, sp);
62
63     V_VT(retv) = VT_DISPATCH;
64     V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(constr);
65     IDispatchEx_AddRef(_IDispatchEx_(constr));
66     return S_OK;
67 }
68
69 static HRESULT JSGlobal_NaN(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
70         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
71 {
72     FIXME("\n");
73     return E_NOTIMPL;
74 }
75
76 static HRESULT JSGlobal_Infinity(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
77         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
78 {
79     FIXME("\n");
80     return E_NOTIMPL;
81 }
82
83 static HRESULT JSGlobal_Array(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
84         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
85 {
86     TRACE("\n");
87
88     return constructor_call(dispex->ctx->array_constr, lcid, flags, dp, retv, ei, sp);
89 }
90
91 static HRESULT JSGlobal_Boolean(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
92         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
93 {
94     TRACE("\n");
95
96     return constructor_call(dispex->ctx->bool_constr, lcid, flags, dp, retv, ei, sp);
97 }
98
99 static HRESULT JSGlobal_Date(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
100         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
101 {
102     FIXME("\n");
103     return E_NOTIMPL;
104 }
105
106 static HRESULT JSGlobal_Function(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
107         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
108 {
109     FIXME("\n");
110     return E_NOTIMPL;
111 }
112
113 static HRESULT JSGlobal_Number(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
114         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
115 {
116     TRACE("\n");
117
118     return constructor_call(dispex->ctx->number_constr, lcid, flags, dp, retv, ei, sp);
119 }
120
121 static HRESULT JSGlobal_Object(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
122         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
123 {
124     TRACE("\n");
125
126     return constructor_call(dispex->ctx->object_constr, lcid, flags, dp, retv, ei, sp);
127 }
128
129 static HRESULT JSGlobal_String(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
130         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
131 {
132     TRACE("\n");
133
134     return constructor_call(dispex->ctx->string_constr, lcid, flags, dp, retv, ei, sp);
135 }
136
137 static HRESULT JSGlobal_RegExp(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
138         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
139 {
140     TRACE("\n");
141
142     return constructor_call(dispex->ctx->regexp_constr, lcid, flags, dp, retv, ei, sp);
143 }
144
145 static HRESULT JSGlobal_ActiveXObject(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
146         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
147 {
148     FIXME("\n");
149     return E_NOTIMPL;
150 }
151
152 static HRESULT JSGlobal_VBArray(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
153         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
154 {
155     FIXME("\n");
156     return E_NOTIMPL;
157 }
158
159 static HRESULT JSGlobal_Enumerator(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
160         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
161 {
162     FIXME("\n");
163     return E_NOTIMPL;
164 }
165
166 static HRESULT JSGlobal_escape(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
167         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
168 {
169     FIXME("\n");
170     return E_NOTIMPL;
171 }
172
173 /* ECMA-262 3rd Edition    15.1.2.1 */
174 static HRESULT JSGlobal_eval(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
175         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
176 {
177     parser_ctx_t *parser_ctx;
178     VARIANT *arg;
179     HRESULT hres;
180
181     TRACE("\n");
182
183     if(!arg_cnt(dp)) {
184         if(retv)
185             V_VT(retv) = VT_EMPTY;
186         return S_OK;
187     }
188
189     arg = get_arg(dp, 0);
190     if(V_VT(arg) != VT_BSTR) {
191         if(retv) {
192             V_VT(retv) = VT_EMPTY;
193             return VariantCopy(retv, arg);
194         }
195         return S_OK;
196     }
197
198     if(!dispex->ctx->exec_ctx) {
199         FIXME("No active exec_ctx\n");
200         return E_UNEXPECTED;
201     }
202
203     TRACE("parsing %s\n", debugstr_w(V_BSTR(arg)));
204     hres = script_parse(dispex->ctx, V_BSTR(arg), &parser_ctx);
205     if(FAILED(hres)) {
206         FIXME("parse failed: %08x\n", hres);
207         return hres;
208     }
209
210     hres = exec_source(dispex->ctx->exec_ctx, parser_ctx, parser_ctx->source, ei, retv);
211     parser_release(parser_ctx);
212
213     return hres;
214 }
215
216 static HRESULT JSGlobal_isNaN(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
217         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
218 {
219     FIXME("\n");
220     return E_NOTIMPL;
221 }
222
223 static HRESULT JSGlobal_isFinite(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
224         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
225 {
226     FIXME("\n");
227     return E_NOTIMPL;
228 }
229
230 static HRESULT JSGlobal_parseInt(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
231         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
232 {
233     return E_NOTIMPL;
234 }
235
236 static HRESULT JSGlobal_parseFloat(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
237         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
238 {
239     FIXME("\n");
240     return E_NOTIMPL;
241 }
242
243 static HRESULT JSGlobal_unescape(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
244         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
245 {
246     FIXME("\n");
247     return E_NOTIMPL;
248 }
249
250 static HRESULT JSGlobal_GetObject(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
251         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
252 {
253     FIXME("\n");
254     return E_NOTIMPL;
255 }
256
257 static HRESULT JSGlobal_ScriptEngine(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
258         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
259 {
260     FIXME("\n");
261     return E_NOTIMPL;
262 }
263
264 static HRESULT JSGlobal_ScriptEngineMajorVersion(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
265         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
266 {
267     FIXME("\n");
268     return E_NOTIMPL;
269 }
270
271 static HRESULT JSGlobal_ScriptEngineMinorVersion(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
272         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
273 {
274     FIXME("\n");
275     return E_NOTIMPL;
276 }
277
278 static HRESULT JSGlobal_ScriptEngineBuildVersion(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
279         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
280 {
281     FIXME("\n");
282     return E_NOTIMPL;
283 }
284
285 static HRESULT JSGlobal_CollectGarbage(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
286         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
287 {
288     FIXME("\n");
289     return E_NOTIMPL;
290 }
291
292 static const builtin_prop_t JSGlobal_props[] = {
293     {ActiveXObjectW,             JSGlobal_ActiveXObject,             PROPF_METHOD},
294     {ArrayW,                     JSGlobal_Array,                     PROPF_CONSTR},
295     {BooleanW,                   JSGlobal_Boolean,                   PROPF_CONSTR},
296     {CollectGarbageW,            JSGlobal_CollectGarbage,            PROPF_METHOD},
297     {DateW,                      JSGlobal_Date,                      PROPF_CONSTR},
298     {EnumeratorW,                JSGlobal_Enumerator,                PROPF_METHOD},
299     {FunctionW,                  JSGlobal_Function,                  PROPF_CONSTR},
300     {GetObjectW,                 JSGlobal_GetObject,                 PROPF_METHOD},
301     {InfinityW,                  JSGlobal_Infinity,                  0},
302 /*  {MathW,                      JSGlobal_Math,                      0},  */
303     {NaNW,                       JSGlobal_NaN,                       0},
304     {NumberW,                    JSGlobal_Number,                    PROPF_CONSTR},
305     {ObjectW,                    JSGlobal_Object,                    PROPF_CONSTR},
306     {RegExpW,                    JSGlobal_RegExp,                    PROPF_CONSTR},
307     {ScriptEngineW,              JSGlobal_ScriptEngine,              PROPF_METHOD},
308     {ScriptEngineBuildVersionW,  JSGlobal_ScriptEngineBuildVersion,  PROPF_METHOD},
309     {ScriptEngineMajorVersionW,  JSGlobal_ScriptEngineMajorVersion,  PROPF_METHOD},
310     {ScriptEngineMinorVersionW,  JSGlobal_ScriptEngineMinorVersion,  PROPF_METHOD},
311     {StringW,                    JSGlobal_String,                    PROPF_CONSTR},
312     {VBArrayW,                   JSGlobal_VBArray,                   PROPF_METHOD},
313     {escapeW,                    JSGlobal_escape,                    PROPF_METHOD},
314     {evalW,                      JSGlobal_eval,                      PROPF_METHOD|1},
315     {isFiniteW,                  JSGlobal_isFinite,                  PROPF_METHOD},
316     {isNaNW,                     JSGlobal_isNaN,                     PROPF_METHOD},
317     {parseFloatW,                JSGlobal_parseFloat,                PROPF_METHOD},
318     {parseIntW,                  JSGlobal_parseInt,                  PROPF_METHOD|2},
319     {unescapeW,                  JSGlobal_unescape,                  PROPF_METHOD}
320 };
321
322 static const builtin_info_t JSGlobal_info = {
323     JSCLASS_GLOBAL,
324     {NULL, NULL, 0},
325     sizeof(JSGlobal_props)/sizeof(*JSGlobal_props),
326     JSGlobal_props,
327     NULL,
328     NULL
329 };
330
331 static HRESULT init_constructors(script_ctx_t *ctx)
332 {
333     HRESULT hres;
334
335     hres = create_array_constr(ctx, &ctx->array_constr);
336     if(FAILED(hres))
337         return hres;
338
339     hres = create_bool_constr(ctx, &ctx->bool_constr);
340     if(FAILED(hres))
341         return hres;
342
343     hres = create_number_constr(ctx, &ctx->number_constr);
344     if(FAILED(hres))
345         return hres;
346
347     hres = create_object_constr(ctx, &ctx->object_constr);
348     if(FAILED(hres))
349         return hres;
350
351     hres = create_object_constr(ctx, &ctx->regexp_constr);
352     if(FAILED(hres))
353         return hres;
354
355     hres = create_string_constr(ctx, &ctx->string_constr);
356     if(FAILED(hres))
357         return hres;
358
359     return S_OK;
360 }
361
362 HRESULT init_global(script_ctx_t *ctx)
363 {
364     DispatchEx *math;
365     VARIANT var;
366     HRESULT hres;
367
368     if(ctx->global)
369         return S_OK;
370
371     hres = init_constructors(ctx);
372     if(FAILED(hres))
373         return hres;
374
375     hres = create_dispex(ctx, &JSGlobal_info, NULL, &ctx->global);
376     if(FAILED(hres))
377         return hres;
378
379     hres = create_math(ctx, &math);
380     if(FAILED(hres))
381         return hres;
382
383     V_VT(&var) = VT_DISPATCH;
384     V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(math);
385     hres = jsdisp_propput_name(ctx->global, MathW, ctx->lcid, &var, NULL/*FIXME*/, NULL/*FIXME*/);
386     jsdisp_release(math);
387
388     return hres;
389 }