2 * Copyright 2008 Jacek Caban for CodeWeavers
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.
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.
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
22 #include "wine/debug.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(jscript
);
28 builtin_invoke_t value_proc
;
30 source_elements_t
*source
;
31 parameter_t
*parameters
;
32 scope_chain_t
*scope_chain
;
39 static const WCHAR prototypeW
[] = {'p','r','o','t','o','t', 'y', 'p','e',0};
41 static const WCHAR lengthW
[] = {'l','e','n','g','t','h',0};
42 static const WCHAR toStringW
[] = {'t','o','S','t','r','i','n','g',0};
43 static const WCHAR toLocaleStringW
[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
44 static const WCHAR applyW
[] = {'a','p','p','l','y',0};
45 static const WCHAR callW
[] = {'c','a','l','l',0};
46 static const WCHAR hasOwnPropertyW
[] = {'h','a','s','O','w','n','P','r','o','p','e','r','t','y',0};
47 static const WCHAR propertyIsEnumerableW
[] = {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
48 static const WCHAR isPrototypeOfW
[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
50 static IDispatch
*get_this(DISPPARAMS
*dp
)
54 for(i
=0; i
< dp
->cNamedArgs
; i
++) {
55 if(dp
->rgdispidNamedArgs
[i
] == DISPID_THIS
) {
56 if(V_VT(dp
->rgvarg
+i
) == VT_DISPATCH
)
57 return V_DISPATCH(dp
->rgvarg
+i
);
59 WARN("This is not VT_DISPATCH\n");
64 TRACE("no this passed\n");
68 static HRESULT
init_parameters(DispatchEx
*var_disp
, FunctionInstance
*function
, LCID lcid
, DISPPARAMS
*dp
,
69 jsexcept_t
*ei
, IServiceProvider
*caller
)
76 V_VT(&var_empty
) = VT_EMPTY
;
77 cargs
= dp
->cArgs
- dp
->cNamedArgs
;
79 for(param
= function
->parameters
; param
; param
= param
->next
) {
80 hres
= jsdisp_propput_name(var_disp
, param
->identifier
, lcid
,
81 i
< cargs
? dp
->rgvarg
+ dp
->cArgs
-1 - i
: &var_empty
,
92 static HRESULT
init_arguments(DispatchEx
*arg_disp
, FunctionInstance
*function
, LCID lcid
, DISPPARAMS
*dp
,
93 jsexcept_t
*ei
, IServiceProvider
*caller
)
99 for(i
=0; i
< dp
->cArgs
-dp
->cNamedArgs
; i
++) {
100 hres
= jsdisp_propput_idx(arg_disp
, i
, lcid
, dp
->rgvarg
+dp
->cArgs
-1-i
, ei
, caller
);
106 V_I4(&var
) = dp
->cArgs
- dp
->cNamedArgs
;
107 return jsdisp_propput_name(arg_disp
, lengthW
, lcid
, &var
, ei
, caller
);
110 static HRESULT
create_var_disp(FunctionInstance
*function
, LCID lcid
, DISPPARAMS
*dp
, jsexcept_t
*ei
,
111 IServiceProvider
*caller
, DispatchEx
**ret
)
113 DispatchEx
*var_disp
, *arg_disp
;
116 static const WCHAR argumentsW
[] = {'a','r','g','u','m','e','n','t','s',0};
118 hres
= create_dispex(function
->dispex
.ctx
, NULL
, NULL
, &var_disp
);
122 hres
= create_dispex(function
->dispex
.ctx
, NULL
, NULL
, &arg_disp
);
123 if(SUCCEEDED(hres
)) {
124 hres
= init_arguments(arg_disp
, function
, lcid
, dp
, ei
, caller
);
125 if(SUCCEEDED(hres
)) {
128 V_VT(&var
) = VT_DISPATCH
;
129 V_DISPATCH(&var
) = (IDispatch
*)_IDispatchEx_(arg_disp
);
130 hres
= jsdisp_propput_name(var_disp
, argumentsW
, lcid
, &var
, ei
, caller
);
133 jsdisp_release(arg_disp
);
137 hres
= init_parameters(var_disp
, function
, lcid
, dp
, ei
, caller
);
139 jsdisp_release(var_disp
);
147 static HRESULT
invoke_source(FunctionInstance
*function
, IDispatch
*this_obj
, LCID lcid
, DISPPARAMS
*dp
,
148 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*caller
)
150 DispatchEx
*var_disp
;
151 exec_ctx_t
*exec_ctx
;
152 scope_chain_t
*scope
;
155 if(!function
->source
) {
156 FIXME("no source\n");
160 hres
= create_var_disp(function
, lcid
, dp
, ei
, caller
, &var_disp
);
164 hres
= scope_push(function
->scope_chain
, var_disp
, &scope
);
165 if(SUCCEEDED(hres
)) {
166 hres
= create_exec_ctx(this_obj
, var_disp
, scope
, &exec_ctx
);
167 scope_release(scope
);
172 hres
= exec_source(exec_ctx
, function
->parser
, function
->source
, ei
, retv
);
173 exec_release(exec_ctx
);
178 static HRESULT
invoke_function(FunctionInstance
*function
, LCID lcid
, DISPPARAMS
*dp
,
179 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*caller
)
183 if(!(this_obj
= get_this(dp
)))
184 this_obj
= (IDispatch
*)_IDispatchEx_(function
->dispex
.ctx
->script_disp
);
186 return invoke_source(function
, this_obj
, lcid
, dp
, retv
, ei
, caller
);
189 static HRESULT
invoke_constructor(FunctionInstance
*function
, LCID lcid
, DISPPARAMS
*dp
,
190 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*caller
)
192 DispatchEx
*this_obj
;
195 hres
= create_object(function
->dispex
.ctx
, &function
->dispex
, &this_obj
);
199 hres
= invoke_source(function
, (IDispatch
*)_IDispatchEx_(this_obj
), lcid
, dp
, retv
, ei
, caller
);
201 jsdisp_release(this_obj
);
205 V_VT(retv
) = VT_DISPATCH
;
206 V_DISPATCH(retv
) = (IDispatch
*)_IDispatchEx_(this_obj
);
210 static HRESULT
invoke_value_proc(FunctionInstance
*function
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
211 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*caller
)
213 DispatchEx
*this_obj
= NULL
;
214 IDispatch
*this_disp
;
217 this_disp
= get_this(dp
);
219 this_obj
= iface_to_jsdisp((IUnknown
*)this_disp
);
221 hres
= function
->value_proc(this_obj
? this_obj
: function
->dispex
.ctx
->script_disp
, lcid
,
222 flags
, dp
, retv
, ei
, caller
);
225 jsdisp_release(this_obj
);
229 static HRESULT
function_to_string(FunctionInstance
*function
, BSTR
*ret
)
233 if(function
->value_proc
) {
234 FIXME("Builtin functions not implemented\n");
238 str
= SysAllocStringLen(function
->src_str
, function
->src_len
);
240 return E_OUTOFMEMORY
;
246 static HRESULT
Function_length(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
247 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*sp
)
249 FunctionInstance
*This
= (FunctionInstance
*)dispex
;
251 TRACE("%p %d\n", This
, This
->length
);
254 case DISPATCH_PROPERTYGET
:
256 V_I4(retv
) = This
->length
;
259 FIXME("unimplemented flags %x\n", flags
);
266 static HRESULT
Function_toString(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
267 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*sp
)
269 FunctionInstance
*function
;
275 if(!is_class(dispex
, JSCLASS_FUNCTION
)) {
276 FIXME("throw TypeError\n");
280 function
= (FunctionInstance
*)dispex
;
282 hres
= function_to_string(function
, &str
);
287 V_VT(retv
) = VT_BSTR
;
295 static HRESULT
Function_toLocaleString(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
296 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*sp
)
302 static HRESULT
Function_apply(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
303 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*sp
)
309 static HRESULT
Function_call(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
310 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*sp
)
316 static HRESULT
Function_hasOwnProperty(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
317 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*sp
)
323 static HRESULT
Function_propertyIsEnumerable(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
324 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*sp
)
330 static HRESULT
Function_isPrototypeOf(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
331 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*sp
)
337 HRESULT
Function_value(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
338 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*caller
)
340 FunctionInstance
*function
;
344 if(dispex
->builtin_info
->class != JSCLASS_FUNCTION
) {
345 ERR("dispex is not a function\n");
349 function
= (FunctionInstance
*)dispex
;
352 case DISPATCH_METHOD
:
353 if(function
->value_proc
)
354 return invoke_value_proc(function
, lcid
, flags
, dp
, retv
, ei
, caller
);
356 return invoke_function(function
, lcid
, dp
, retv
, ei
, caller
);
358 case DISPATCH_PROPERTYGET
: {
362 hres
= function_to_string(function
, &str
);
366 V_VT(retv
) = VT_BSTR
;
371 case DISPATCH_CONSTRUCT
:
372 if(function
->value_proc
)
373 return invoke_value_proc(function
, lcid
, flags
, dp
, retv
, ei
, caller
);
375 return invoke_constructor(function
, lcid
, dp
, retv
, ei
, caller
);
378 FIXME("not implemented flags %x\n", flags
);
385 static void Function_destructor(DispatchEx
*dispex
)
387 FunctionInstance
*This
= (FunctionInstance
*)dispex
;
390 parser_release(This
->parser
);
391 if(This
->scope_chain
)
392 scope_release(This
->scope_chain
);
396 static const builtin_prop_t Function_props
[] = {
397 {applyW
, Function_apply
, PROPF_METHOD
},
398 {callW
, Function_call
, PROPF_METHOD
},
399 {hasOwnPropertyW
, Function_hasOwnProperty
, PROPF_METHOD
},
400 {isPrototypeOfW
, Function_isPrototypeOf
, PROPF_METHOD
},
401 {lengthW
, Function_length
, 0},
402 {propertyIsEnumerableW
, Function_propertyIsEnumerable
, PROPF_METHOD
},
403 {toLocaleStringW
, Function_toLocaleString
, PROPF_METHOD
},
404 {toStringW
, Function_toString
, PROPF_METHOD
}
407 static const builtin_info_t Function_info
= {
409 {NULL
, Function_value
, 0},
410 sizeof(Function_props
)/sizeof(*Function_props
),
416 static HRESULT
FunctionConstr_value(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
417 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*sp
)
423 static HRESULT
FunctionProt_value(DispatchEx
*dispex
, LCID lcid
, WORD flags
, DISPPARAMS
*dp
,
424 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*sp
)
430 static HRESULT
create_function(script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, DWORD flags
,
431 BOOL funcprot
, DispatchEx
*prototype
, FunctionInstance
**ret
)
433 FunctionInstance
*function
;
436 function
= heap_alloc_zero(sizeof(FunctionInstance
));
438 return E_OUTOFMEMORY
;
441 hres
= init_dispex(&function
->dispex
, ctx
, &Function_info
, prototype
);
442 else if(builtin_info
)
443 hres
= init_dispex_from_constr(&function
->dispex
, ctx
, builtin_info
, ctx
->function_constr
);
445 hres
= init_dispex_from_constr(&function
->dispex
, ctx
, &Function_info
, ctx
->function_constr
);
449 function
->flags
= flags
;
450 function
->length
= flags
& PROPF_ARGMASK
;
456 static HRESULT
set_prototype(script_ctx_t
*ctx
, DispatchEx
*dispex
, DispatchEx
*prototype
)
461 V_VT(&var
) = VT_DISPATCH
;
462 V_DISPATCH(&var
) = (IDispatch
*)_IDispatchEx_(prototype
);
463 memset(&jsexcept
, 0, sizeof(jsexcept
));
465 return jsdisp_propput_name(dispex
, prototypeW
, ctx
->lcid
, &var
, &jsexcept
, NULL
/*FIXME*/);
468 HRESULT
create_builtin_function(script_ctx_t
*ctx
, builtin_invoke_t value_proc
,
469 const builtin_info_t
*builtin_info
, DWORD flags
, DispatchEx
*prototype
, DispatchEx
**ret
)
471 FunctionInstance
*function
;
474 hres
= create_function(ctx
, builtin_info
, flags
, FALSE
, NULL
, &function
);
478 hres
= set_prototype(ctx
, &function
->dispex
, prototype
);
480 jsdisp_release(&function
->dispex
);
484 function
->value_proc
= value_proc
;
486 *ret
= &function
->dispex
;
490 HRESULT
create_source_function(parser_ctx_t
*ctx
, parameter_t
*parameters
, source_elements_t
*source
,
491 scope_chain_t
*scope_chain
, const WCHAR
*src_str
, DWORD src_len
, DispatchEx
**ret
)
493 FunctionInstance
*function
;
494 DispatchEx
*prototype
;
499 hres
= create_object(ctx
->script
, NULL
, &prototype
);
503 hres
= create_function(ctx
->script
, NULL
, PROPF_CONSTR
, FALSE
, NULL
, &function
);
504 if(SUCCEEDED(hres
)) {
505 hres
= set_prototype(ctx
->script
, &function
->dispex
, prototype
);
507 jsdisp_release(&function
->dispex
);
509 jsdisp_release(prototype
);
513 function
->source
= source
;
514 function
->parameters
= parameters
;
517 scope_addref(scope_chain
);
518 function
->scope_chain
= scope_chain
;
522 function
->parser
= ctx
;
524 for(iter
= parameters
; iter
; iter
= iter
->next
)
526 function
->length
= length
;
528 function
->src_str
= src_str
;
529 function
->src_len
= src_len
;
531 *ret
= &function
->dispex
;
535 HRESULT
init_function_constr(script_ctx_t
*ctx
, DispatchEx
*object_prototype
)
537 FunctionInstance
*prot
, *constr
;
540 hres
= create_function(ctx
, NULL
, PROPF_CONSTR
, TRUE
, object_prototype
, &prot
);
544 prot
->value_proc
= FunctionProt_value
;
546 hres
= create_function(ctx
, NULL
, PROPF_CONSTR
, TRUE
, &prot
->dispex
, &constr
);
547 if(SUCCEEDED(hres
)) {
548 constr
->value_proc
= FunctionConstr_value
;
549 hres
= set_prototype(ctx
, &constr
->dispex
, &prot
->dispex
);
551 jsdisp_release(&constr
->dispex
);
553 jsdisp_release(&prot
->dispex
);
557 ctx
->function_constr
= &constr
->dispex
;