jscript: Use jsdisp_propput_dontenum where appropriate.
[wine] / dlls / jscript / function.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 <assert.h>
20
21 #include "jscript.h"
22 #include "engine.h"
23
24 #include "wine/debug.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
27
28 typedef struct {
29     jsdisp_t dispex;
30     builtin_invoke_t value_proc;
31     const WCHAR *name;
32     DWORD flags;
33     scope_chain_t *scope_chain;
34     bytecode_t *code;
35     function_code_t *func_code;
36     DWORD length;
37     jsdisp_t *arguments;
38 } FunctionInstance;
39
40 static inline FunctionInstance *function_from_vdisp(vdisp_t *vdisp)
41 {
42     return (FunctionInstance*)vdisp->u.jsdisp;
43 }
44
45 static inline FunctionInstance *function_this(vdisp_t *jsthis)
46 {
47     return is_vclass(jsthis, JSCLASS_FUNCTION) ? function_from_vdisp(jsthis) : NULL;
48 }
49
50 static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
51
52 static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
53 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
54 static const WCHAR applyW[] = {'a','p','p','l','y',0};
55 static const WCHAR callW[] = {'c','a','l','l',0};
56 static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0};
57
58 static HRESULT init_parameters(jsdisp_t *var_disp, FunctionInstance *function, unsigned argc, jsval_t *argv)
59 {
60     DWORD i=0;
61     HRESULT hres;
62
63     for(i=0; i < function->func_code->param_cnt; i++) {
64         hres = jsdisp_propput_name(var_disp, function->func_code->params[i],
65                 i < argc ? argv[i] : jsval_undefined());
66         if(FAILED(hres))
67             return hres;
68     }
69
70     return S_OK;
71 }
72
73 static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
74         jsval_t *r)
75 {
76     FIXME("\n");
77     return E_NOTIMPL;
78 }
79
80 static const builtin_info_t Arguments_info = {
81     JSCLASS_ARGUMENTS,
82     {NULL, Arguments_value, 0},
83     0, NULL,
84     NULL,
85     NULL
86 };
87
88 static HRESULT create_arguments(script_ctx_t *ctx, IDispatch *calee, unsigned argc, jsval_t *argv, jsdisp_t **ret)
89 {
90     jsdisp_t *args;
91     DWORD i;
92     HRESULT hres;
93
94     static const WCHAR caleeW[] = {'c','a','l','l','e','e',0};
95
96     args = heap_alloc_zero(sizeof(jsdisp_t));
97     if(!args)
98         return E_OUTOFMEMORY;
99
100     hres = init_dispex_from_constr(args, ctx, &Arguments_info, ctx->object_constr);
101     if(FAILED(hres)) {
102         heap_free(args);
103         return hres;
104     }
105
106     for(i=0; i < argc; i++) {
107         WCHAR buf[12];
108
109         static const WCHAR formatW[] = {'%','d',0};
110
111         sprintfW(buf, formatW, i);
112         hres = jsdisp_propput_dontenum(args, buf, argv[i]);
113         if(FAILED(hres))
114             break;
115     }
116
117     if(SUCCEEDED(hres)) {
118         hres = jsdisp_propput_dontenum(args, lengthW, jsval_number(argc));
119
120         if(SUCCEEDED(hres))
121             hres = jsdisp_propput_dontenum(args, caleeW, jsval_disp(calee));
122     }
123
124     if(FAILED(hres)) {
125         jsdisp_release(args);
126         return hres;
127     }
128
129     *ret = args;
130     return S_OK;
131 }
132
133 static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, jsdisp_t *arg_disp,
134         unsigned argc, jsval_t *argv, jsdisp_t **ret)
135 {
136     jsdisp_t *var_disp;
137     HRESULT hres;
138
139     hres = create_dispex(ctx, NULL, NULL, &var_disp);
140     if(FAILED(hres))
141         return hres;
142
143     hres = jsdisp_propput_name(var_disp, argumentsW, jsval_obj(arg_disp));
144     if(SUCCEEDED(hres))
145         hres = init_parameters(var_disp, function, argc, argv);
146     if(FAILED(hres)) {
147         jsdisp_release(var_disp);
148         return hres;
149     }
150
151     *ret = var_disp;
152     return S_OK;
153 }
154
155 static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv,
156         jsval_t *r)
157 {
158     jsdisp_t *var_disp, *arg_disp;
159     exec_ctx_t *exec_ctx;
160     scope_chain_t *scope;
161     HRESULT hres;
162
163     if(!function->func_code) {
164         FIXME("no source\n");
165         return E_FAIL;
166     }
167
168     hres = create_arguments(ctx, to_disp(&function->dispex), argc, argv, &arg_disp);
169     if(FAILED(hres))
170         return hres;
171
172     hres = create_var_disp(ctx, function, arg_disp, argc, argv, &var_disp);
173     if(FAILED(hres)) {
174         jsdisp_release(arg_disp);
175         return hres;
176     }
177
178     hres = scope_push(function->scope_chain, var_disp, to_disp(var_disp), &scope);
179     if(SUCCEEDED(hres)) {
180         hres = create_exec_ctx(ctx, this_obj, var_disp, scope, FALSE, &exec_ctx);
181         scope_release(scope);
182     }
183     jsdisp_release(var_disp);
184     if(SUCCEEDED(hres)) {
185         jsdisp_t *prev_args;
186
187         prev_args = function->arguments;
188         function->arguments = arg_disp;
189         hres = exec_source(exec_ctx, function->code, function->func_code, FALSE, r);
190         function->arguments = prev_args;
191     }
192
193     jsdisp_release(arg_disp);
194     exec_release(exec_ctx);
195     return hres;
196 }
197
198 static HRESULT invoke_constructor(script_ctx_t *ctx, FunctionInstance *function, unsigned argc, jsval_t *argv,
199         jsval_t *r)
200 {
201     jsdisp_t *this_obj;
202     jsval_t var;
203     HRESULT hres;
204
205     hres = create_object(ctx, &function->dispex, &this_obj);
206     if(FAILED(hres))
207         return hres;
208
209     hres = invoke_source(ctx, function, to_disp(this_obj), argc, argv, &var);
210     if(FAILED(hres)) {
211         jsdisp_release(this_obj);
212         return hres;
213     }
214
215     if(is_object_instance(var)) {
216         jsdisp_release(this_obj);
217         *r = var;
218     }else {
219         jsval_release(var);
220         *r = jsval_obj(this_obj);
221     }
222     return S_OK;
223 }
224
225 static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_disp, WORD flags,
226         unsigned argc, jsval_t *argv, jsval_t *r)
227 {
228     vdisp_t vthis;
229     HRESULT hres;
230
231     if(this_disp)
232         set_disp(&vthis, this_disp);
233     else if(ctx->host_global)
234         set_disp(&vthis, ctx->host_global);
235     else
236         set_jsdisp(&vthis, ctx->global);
237
238     hres = function->value_proc(ctx, &vthis, flags, argc, argv, r);
239
240     vdisp_release(&vthis);
241     return hres;
242 }
243
244 static HRESULT call_function(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj,
245         unsigned argc, jsval_t *argv, jsval_t *r)
246 {
247     if(function->value_proc)
248         return invoke_value_proc(ctx, function, this_obj, DISPATCH_METHOD, argc, argv, r);
249
250     return invoke_source(ctx, function, this_obj, argc, argv, r);
251 }
252
253 static HRESULT function_to_string(FunctionInstance *function, jsstr_t **ret)
254 {
255     jsstr_t *str;
256
257     static const WCHAR native_prefixW[] = {'\n','f','u','n','c','t','i','o','n',' '};
258     static const WCHAR native_suffixW[] =
259         {'(',')',' ','{','\n',' ',' ',' ',' ','[','n','a','t','i','v','e',' ','c','o','d','e',']','\n','}','\n'};
260
261     if(function->value_proc) {
262         DWORD name_len;
263
264         name_len = strlenW(function->name);
265         str = jsstr_alloc_buf((sizeof(native_prefixW)+sizeof(native_suffixW))/sizeof(WCHAR) + name_len);
266         if(!str)
267             return E_OUTOFMEMORY;
268
269         memcpy(str->str, native_prefixW, sizeof(native_prefixW));
270         memcpy(str->str + sizeof(native_prefixW)/sizeof(WCHAR), function->name, name_len*sizeof(WCHAR));
271         memcpy(str->str + sizeof(native_prefixW)/sizeof(WCHAR) + name_len, native_suffixW, sizeof(native_suffixW));
272     }else {
273         str = jsstr_alloc_len(function->func_code->source, function->func_code->source_len);
274         if(!str)
275             return E_OUTOFMEMORY;
276     }
277
278     *ret = str;
279     return S_OK;
280 }
281
282 HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
283 {
284     FunctionInstance *function;
285
286     TRACE("func %p this %p\n", func_this, jsthis);
287
288     assert(is_class(func_this, JSCLASS_FUNCTION));
289     function = (FunctionInstance*)func_this;
290
291     if(function->value_proc)
292         return invoke_value_proc(function->dispex.ctx, function, jsthis, flags, argc, argv, r);
293
294     if(flags == DISPATCH_CONSTRUCT)
295         return invoke_constructor(function->dispex.ctx, function, argc, argv, r);
296
297     assert(flags == DISPATCH_METHOD);
298     return invoke_source(function->dispex.ctx, function, jsthis, argc, argv, r);
299 }
300
301 static HRESULT Function_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
302         jsval_t *r)
303 {
304     FunctionInstance *This = function_from_vdisp(jsthis);
305
306     TRACE("%p %d\n", This, This->length);
307
308     switch(flags) {
309     case DISPATCH_PROPERTYGET:
310         *r = jsval_number(This->length);
311         break;
312     default:
313         FIXME("unimplemented flags %x\n", flags);
314         return E_NOTIMPL;
315     }
316
317     return S_OK;
318 }
319
320 static HRESULT Function_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
321         jsval_t *r)
322 {
323     FunctionInstance *function;
324     jsstr_t *str;
325     HRESULT hres;
326
327     TRACE("\n");
328
329     if(!(function = function_this(jsthis)))
330         return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
331
332     hres = function_to_string(function, &str);
333     if(FAILED(hres))
334         return hres;
335
336     if(r)
337         *r = jsval_string(str);
338     else
339         jsstr_release(str);
340     return S_OK;
341 }
342
343 static HRESULT array_to_args(script_ctx_t *ctx, jsdisp_t *arg_array, unsigned *argc, jsval_t **ret)
344 {
345     jsval_t *argv, val;
346     DWORD length, i;
347     HRESULT hres;
348
349     hres = jsdisp_propget_name(arg_array, lengthW, &val);
350     if(FAILED(hres))
351         return hres;
352
353     hres = to_uint32(ctx, val, &length);
354     jsval_release(val);
355     if(FAILED(hres))
356         return hres;
357
358     argv = heap_alloc(length * sizeof(*argv));
359     if(!argv)
360         return E_OUTOFMEMORY;
361
362     for(i=0; i<length; i++) {
363         hres = jsdisp_get_idx(arg_array, i, argv+i);
364         if(hres == DISP_E_UNKNOWNNAME) {
365             argv[i] = jsval_undefined();
366         }else if(FAILED(hres)) {
367             while(i--)
368                 jsval_release(argv[i]);
369             heap_free(argv);
370             return hres;
371         }
372     }
373
374     *argc = length;
375     *ret = argv;
376     return S_OK;
377 }
378
379 static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
380 {
381     FunctionInstance *function;
382     jsval_t *args = NULL;
383     unsigned i, cnt = 0;
384     IDispatch *this_obj = NULL;
385     HRESULT hres = S_OK;
386
387     TRACE("\n");
388
389     if(!(function = function_this(jsthis)))
390         return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
391
392     if(argc) {
393         if(!is_undefined(argv[0]) && !is_null(argv[0])) {
394             hres = to_object(ctx, argv[0], &this_obj);
395             if(FAILED(hres))
396                 return hres;
397         }
398     }
399
400     if(argc >= 2) {
401         jsdisp_t *arg_array = NULL;
402
403         if(is_object_instance(argv[1])) {
404             arg_array = iface_to_jsdisp((IUnknown*)get_object(argv[1]));
405             if(arg_array &&
406                (!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS) )) {
407                 jsdisp_release(arg_array);
408                 arg_array = NULL;
409             }
410         }
411
412         if(arg_array) {
413             hres = array_to_args(ctx, arg_array, &cnt, &args);
414             jsdisp_release(arg_array);
415         }else {
416             FIXME("throw TypeError\n");
417             hres = E_FAIL;
418         }
419     }
420
421     if(SUCCEEDED(hres))
422         hres = call_function(ctx, function, this_obj, cnt, args, r);
423
424     if(this_obj)
425         IDispatch_Release(this_obj);
426     for(i=0; i < cnt; i++)
427         jsval_release(args[i]);
428     heap_free(args);
429     return hres;
430 }
431
432 static HRESULT Function_call(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
433         jsval_t *r)
434 {
435     FunctionInstance *function;
436     IDispatch *this_obj = NULL;
437     unsigned cnt = 0;
438     HRESULT hres;
439
440     TRACE("\n");
441
442     if(!(function = function_this(jsthis)))
443         return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
444
445     if(argc) {
446         if(!is_undefined(argv[0]) && !is_null(argv[0])) {
447             hres = to_object(ctx, argv[0], &this_obj);
448             if(FAILED(hres))
449                 return hres;
450         }
451
452         cnt = argc-1;
453     }
454
455     hres = call_function(ctx, function, this_obj, cnt, argv+1, r);
456
457     if(this_obj)
458         IDispatch_Release(this_obj);
459     return hres;
460 }
461
462 HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
463         jsval_t *r)
464 {
465     FunctionInstance *function;
466
467     TRACE("\n");
468
469     if(!is_vclass(jsthis, JSCLASS_FUNCTION)) {
470         ERR("dispex is not a function\n");
471         return E_FAIL;
472     }
473
474     function = (FunctionInstance*)jsthis->u.jsdisp;
475
476     switch(flags) {
477     case DISPATCH_METHOD:
478         assert(function->value_proc != NULL);
479         return invoke_value_proc(ctx, function, NULL, flags, argc, argv, r);
480
481     case DISPATCH_PROPERTYGET: {
482         HRESULT hres;
483         jsstr_t *str;
484
485         hres = function_to_string(function, &str);
486         if(FAILED(hres))
487             return hres;
488
489         *r = jsval_string(str);
490         break;
491     }
492
493     case DISPATCH_CONSTRUCT:
494         assert(function->value_proc != NULL);
495         return invoke_value_proc(ctx, function, NULL, flags, argc, argv, r);
496
497     default:
498         FIXME("not implemented flags %x\n", flags);
499         return E_NOTIMPL;
500     }
501
502     return S_OK;
503 }
504
505 static HRESULT Function_arguments(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
506         unsigned argc, jsval_t *argv, jsval_t *r)
507 {
508     FunctionInstance *function = (FunctionInstance*)jsthis->u.jsdisp;
509     HRESULT hres = S_OK;
510
511     TRACE("\n");
512
513     switch(flags) {
514     case DISPATCH_PROPERTYGET: {
515         *r = function->arguments ? jsval_obj(jsdisp_addref(function->arguments)) : jsval_null();
516         break;
517     }
518     case DISPATCH_PROPERTYPUT:
519         break;
520     default:
521         FIXME("unimplemented flags %x\n", flags);
522         hres = E_NOTIMPL;
523     }
524
525     return hres;
526 }
527
528 static void Function_destructor(jsdisp_t *dispex)
529 {
530     FunctionInstance *This = (FunctionInstance*)dispex;
531
532     if(This->code)
533         release_bytecode(This->code);
534     if(This->scope_chain)
535         scope_release(This->scope_chain);
536     heap_free(This);
537 }
538
539 static const builtin_prop_t Function_props[] = {
540     {applyW,                 Function_apply,                 PROPF_METHOD|2},
541     {argumentsW,             Function_arguments,             0},
542     {callW,                  Function_call,                  PROPF_METHOD|1},
543     {lengthW,                Function_length,                0},
544     {toStringW,              Function_toString,              PROPF_METHOD}
545 };
546
547 static const builtin_info_t Function_info = {
548     JSCLASS_FUNCTION,
549     {NULL, Function_value, 0},
550     sizeof(Function_props)/sizeof(*Function_props),
551     Function_props,
552     Function_destructor,
553     NULL
554 };
555
556 static const builtin_prop_t FunctionInst_props[] = {
557     {argumentsW,             Function_arguments,             0},
558     {lengthW,                Function_length,                0}
559 };
560
561 static const builtin_info_t FunctionInst_info = {
562     JSCLASS_FUNCTION,
563     {NULL, Function_value, 0},
564     sizeof(FunctionInst_props)/sizeof(*FunctionInst_props),
565     FunctionInst_props,
566     Function_destructor,
567     NULL
568 };
569
570 static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_info, DWORD flags,
571         BOOL funcprot, jsdisp_t *prototype, FunctionInstance **ret)
572 {
573     FunctionInstance *function;
574     HRESULT hres;
575
576     function = heap_alloc_zero(sizeof(FunctionInstance));
577     if(!function)
578         return E_OUTOFMEMORY;
579
580     if(funcprot)
581         hres = init_dispex(&function->dispex, ctx, builtin_info, prototype);
582     else if(builtin_info)
583         hres = init_dispex_from_constr(&function->dispex, ctx, builtin_info, ctx->function_constr);
584     else
585         hres = init_dispex_from_constr(&function->dispex, ctx, &FunctionInst_info, ctx->function_constr);
586     if(FAILED(hres)) {
587         heap_free(function);
588         return hres;
589     }
590
591     function->flags = flags;
592     function->length = flags & PROPF_ARGMASK;
593
594     *ret = function;
595     return S_OK;
596 }
597
598 static inline HRESULT set_prototype(script_ctx_t *ctx, jsdisp_t *dispex, jsdisp_t *prototype)
599 {
600     return jsdisp_propput_dontenum(dispex, prototypeW, jsval_obj(prototype));
601 }
602
603 HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, const WCHAR *name,
604         const builtin_info_t *builtin_info, DWORD flags, jsdisp_t *prototype, jsdisp_t **ret)
605 {
606     FunctionInstance *function;
607     HRESULT hres;
608
609     hres = create_function(ctx, builtin_info, flags, FALSE, NULL, &function);
610     if(FAILED(hres))
611         return hres;
612
613     if(builtin_info)
614         hres = jsdisp_propput_const(&function->dispex, lengthW, jsval_number(function->length));
615     if(SUCCEEDED(hres))
616         hres = set_prototype(ctx, &function->dispex, prototype);
617     if(FAILED(hres)) {
618         jsdisp_release(&function->dispex);
619         return hres;
620     }
621
622     function->value_proc = value_proc;
623     function->name = name;
624
625     *ret = &function->dispex;
626     return S_OK;
627 }
628
629 static HRESULT set_constructor_prop(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_t *prot)
630 {
631     static const WCHAR constructorW[] = {'c','o','n','s','t','r','u','c','t','o','r',0};
632
633     return jsdisp_propput_dontenum(prot, constructorW, jsval_obj(constr));
634 }
635
636 HRESULT create_builtin_constructor(script_ctx_t *ctx, builtin_invoke_t value_proc, const WCHAR *name,
637         const builtin_info_t *builtin_info, DWORD flags, jsdisp_t *prototype, jsdisp_t **ret)
638 {
639     jsdisp_t *constr;
640     HRESULT hres;
641
642     hres = create_builtin_function(ctx, value_proc, name, builtin_info, flags, prototype, &constr);
643     if(FAILED(hres))
644         return hres;
645
646     hres = set_constructor_prop(ctx, constr, prototype);
647     if(FAILED(hres)) {
648         jsdisp_release(constr);
649         return hres;
650     }
651
652     *ret = constr;
653     return S_OK;
654 }
655
656 HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_code_t *func_code,
657         scope_chain_t *scope_chain, jsdisp_t **ret)
658 {
659     FunctionInstance *function;
660     jsdisp_t *prototype;
661     HRESULT hres;
662
663     hres = create_object(ctx, NULL, &prototype);
664     if(FAILED(hres))
665         return hres;
666
667     hres = create_function(ctx, NULL, PROPF_CONSTR, FALSE, NULL, &function);
668     if(SUCCEEDED(hres)) {
669         hres = set_prototype(ctx, &function->dispex, prototype);
670         if(SUCCEEDED(hres))
671             hres = set_constructor_prop(ctx, &function->dispex, prototype);
672         if(FAILED(hres))
673             jsdisp_release(&function->dispex);
674     }
675     jsdisp_release(prototype);
676     if(FAILED(hres))
677         return hres;
678
679     if(scope_chain) {
680         scope_addref(scope_chain);
681         function->scope_chain = scope_chain;
682     }
683
684     bytecode_addref(code);
685     function->code = code;
686     function->func_code = func_code;
687     function->length = function->func_code->param_cnt;
688
689     *ret = &function->dispex;
690     return S_OK;
691 }
692
693 static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *argv, IDispatch **ret)
694 {
695     WCHAR *str = NULL, *ptr;
696     DWORD len = 0, l;
697     bytecode_t *code;
698     jsdisp_t *function;
699     jsstr_t **params = NULL;
700     int i=0, j=0;
701     HRESULT hres = S_OK;
702
703     static const WCHAR function_anonymousW[] = {'f','u','n','c','t','i','o','n',' ','a','n','o','n','y','m','o','u','s','('};
704     static const WCHAR function_beginW[] = {')',' ','{','\n'};
705     static const WCHAR function_endW[] = {'\n','}',0};
706
707     if(argc) {
708         params = heap_alloc(argc*sizeof(*params));
709         if(!params)
710             return E_OUTOFMEMORY;
711
712         if(argc > 2)
713             len = (argc-2)*2; /* separating commas */
714         for(i=0; i < argc; i++) {
715             hres = to_string(ctx, argv[i], params+i);
716             if(FAILED(hres))
717                 break;
718             len += jsstr_length(params[i]);
719         }
720     }
721
722     if(SUCCEEDED(hres)) {
723         len += (sizeof(function_anonymousW) + sizeof(function_beginW) + sizeof(function_endW)) / sizeof(WCHAR);
724         str = heap_alloc(len*sizeof(WCHAR));
725         if(str) {
726             memcpy(str, function_anonymousW, sizeof(function_anonymousW));
727             ptr = str + sizeof(function_anonymousW)/sizeof(WCHAR);
728             if(argc > 1) {
729                 while(1) {
730                     l = jsstr_length(params[j]);
731                     memcpy(ptr, params[j]->str, l*sizeof(WCHAR));
732                     ptr += l;
733                     if(++j == argc-1)
734                         break;
735                     *ptr++ = ',';
736                     *ptr++ = ' ';
737                 }
738             }
739             memcpy(ptr, function_beginW, sizeof(function_beginW));
740             ptr += sizeof(function_beginW)/sizeof(WCHAR);
741             if(argc) {
742                 l = jsstr_length(params[argc-1]);
743                 memcpy(ptr, params[argc-1]->str, l*sizeof(WCHAR));
744                 ptr += l;
745             }
746             memcpy(ptr, function_endW, sizeof(function_endW));
747
748             TRACE("%s\n", debugstr_w(str));
749         }else {
750             hres = E_OUTOFMEMORY;
751         }
752     }
753
754     while(--i >= 0)
755         jsstr_release(params[i]);
756     heap_free(params);
757     if(FAILED(hres))
758         return hres;
759
760     hres = compile_script(ctx, str, NULL, NULL, FALSE, FALSE, &code);
761     heap_free(str);
762     if(FAILED(hres))
763         return hres;
764
765     if(code->global_code.func_cnt != 1 || code->global_code.var_cnt) {
766         ERR("Invalid parser result!\n");
767         release_bytecode(code);
768         return E_UNEXPECTED;
769     }
770
771     hres = create_source_function(ctx, code, code->global_code.funcs, NULL, &function);
772     release_bytecode(code);
773     if(FAILED(hres))
774         return hres;
775
776     *ret = to_disp(function);
777     return S_OK;
778 }
779
780 static HRESULT FunctionConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
781         jsval_t *r)
782 {
783     HRESULT hres;
784
785     TRACE("\n");
786
787     switch(flags) {
788     case DISPATCH_CONSTRUCT: {
789         IDispatch *ret;
790
791         hres = construct_function(ctx, argc, argv, &ret);
792         if(FAILED(hres))
793             return hres;
794
795         *r = jsval_disp(ret);
796         break;
797     }
798     default:
799         FIXME("unimplemented flags %x\n", flags);
800         return E_NOTIMPL;
801     }
802
803     return S_OK;
804 }
805
806 static HRESULT FunctionProt_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
807         jsval_t *r)
808 {
809     FIXME("\n");
810     return E_NOTIMPL;
811 }
812
813 HRESULT init_function_constr(script_ctx_t *ctx, jsdisp_t *object_prototype)
814 {
815     FunctionInstance *prot, *constr;
816     HRESULT hres;
817
818     static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0};
819
820     hres = create_function(ctx, &Function_info, PROPF_CONSTR, TRUE, object_prototype, &prot);
821     if(FAILED(hres))
822         return hres;
823
824     prot->value_proc = FunctionProt_value;
825     prot->name = prototypeW;
826
827     hres = create_function(ctx, &FunctionInst_info, PROPF_CONSTR|1, TRUE, &prot->dispex, &constr);
828     if(SUCCEEDED(hres)) {
829         constr->value_proc = FunctionConstr_value;
830         constr->name = FunctionW;
831         hres = set_prototype(ctx, &constr->dispex, &prot->dispex);
832         if(SUCCEEDED(hres))
833             hres = set_constructor_prop(ctx, &constr->dispex, &prot->dispex);
834         if(FAILED(hres))
835             jsdisp_release(&constr->dispex);
836     }
837     jsdisp_release(&prot->dispex);
838     if(FAILED(hres))
839         return hres;
840
841     ctx->function_constr = &constr->dispex;
842     return S_OK;
843 }