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