Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfunction.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2008 Jacek Caban for CodeWeavers 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #include "jscript.h" 00020 #include "engine.h" 00021 00022 #include "wine/debug.h" 00023 00024 WINE_DEFAULT_DEBUG_CHANNEL(jscript); 00025 00026 typedef struct { 00027 DispatchEx dispex; 00028 builtin_invoke_t value_proc; 00029 const WCHAR *name; 00030 DWORD flags; 00031 source_elements_t *source; 00032 parameter_t *parameters; 00033 scope_chain_t *scope_chain; 00034 parser_ctx_t *parser; 00035 const WCHAR *src_str; 00036 DWORD src_len; 00037 DWORD length; 00038 } FunctionInstance; 00039 00040 static inline FunctionInstance *function_from_vdisp(vdisp_t *vdisp) 00041 { 00042 return (FunctionInstance*)vdisp->u.jsdisp; 00043 } 00044 00045 static inline FunctionInstance *function_this(vdisp_t *jsthis) 00046 { 00047 return is_vclass(jsthis, JSCLASS_FUNCTION) ? function_from_vdisp(jsthis) : NULL; 00048 } 00049 00050 static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0}; 00051 00052 static const WCHAR lengthW[] = {'l','e','n','g','t','h',0}; 00053 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; 00054 static const WCHAR applyW[] = {'a','p','p','l','y',0}; 00055 static const WCHAR callW[] = {'c','a','l','l',0}; 00056 00057 static IDispatch *get_this(DISPPARAMS *dp) 00058 { 00059 DWORD i; 00060 00061 for(i=0; i < dp->cNamedArgs; i++) { 00062 if(dp->rgdispidNamedArgs[i] == DISPID_THIS) { 00063 if(V_VT(dp->rgvarg+i) == VT_DISPATCH) 00064 return V_DISPATCH(dp->rgvarg+i); 00065 00066 WARN("This is not VT_DISPATCH\n"); 00067 return NULL; 00068 } 00069 } 00070 00071 TRACE("no this passed\n"); 00072 return NULL; 00073 } 00074 00075 static HRESULT init_parameters(DispatchEx *var_disp, FunctionInstance *function, DISPPARAMS *dp, 00076 jsexcept_t *ei, IServiceProvider *caller) 00077 { 00078 parameter_t *param; 00079 VARIANT var_empty; 00080 DWORD cargs, i=0; 00081 HRESULT hres; 00082 00083 V_VT(&var_empty) = VT_EMPTY; 00084 cargs = arg_cnt(dp); 00085 00086 for(param = function->parameters; param; param = param->next) { 00087 hres = jsdisp_propput_name(var_disp, param->identifier, 00088 i < cargs ? get_arg(dp,i) : &var_empty, ei, caller); 00089 if(FAILED(hres)) 00090 return hres; 00091 00092 i++; 00093 } 00094 00095 return S_OK; 00096 } 00097 00098 static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00099 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00100 { 00101 FIXME("\n"); 00102 return E_NOTIMPL; 00103 } 00104 00105 static const builtin_info_t Arguments_info = { 00106 JSCLASS_ARGUMENTS, 00107 {NULL, Arguments_value, 0}, 00108 0, NULL, 00109 NULL, 00110 NULL 00111 }; 00112 00113 static HRESULT create_arguments(script_ctx_t *ctx, IDispatch *calee, DISPPARAMS *dp, 00114 jsexcept_t *ei, IServiceProvider *caller, DispatchEx **ret) 00115 { 00116 DispatchEx *args; 00117 VARIANT var; 00118 DWORD i; 00119 HRESULT hres; 00120 00121 static const WCHAR caleeW[] = {'c','a','l','l','e','e',0}; 00122 00123 args = heap_alloc_zero(sizeof(DispatchEx)); 00124 if(!args) 00125 return E_OUTOFMEMORY; 00126 00127 hres = init_dispex_from_constr(args, ctx, &Arguments_info, ctx->object_constr); 00128 if(FAILED(hres)) { 00129 heap_free(args); 00130 return hres; 00131 } 00132 00133 for(i=0; i < arg_cnt(dp); i++) { 00134 hres = jsdisp_propput_idx(args, i, get_arg(dp,i), ei, caller); 00135 if(FAILED(hres)) 00136 break; 00137 } 00138 00139 if(SUCCEEDED(hres)) { 00140 V_VT(&var) = VT_I4; 00141 V_I4(&var) = arg_cnt(dp); 00142 hres = jsdisp_propput_name(args, lengthW, &var, ei, caller); 00143 00144 if(SUCCEEDED(hres)) { 00145 V_VT(&var) = VT_DISPATCH; 00146 V_DISPATCH(&var) = calee; 00147 hres = jsdisp_propput_name(args, caleeW, &var, ei, caller); 00148 } 00149 } 00150 00151 if(FAILED(hres)) { 00152 jsdisp_release(args); 00153 return hres; 00154 } 00155 00156 *ret = args; 00157 return S_OK; 00158 } 00159 00160 static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, DISPPARAMS *dp, jsexcept_t *ei, 00161 IServiceProvider *caller, DispatchEx **ret) 00162 { 00163 DispatchEx *var_disp, *arg_disp; 00164 HRESULT hres; 00165 00166 static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0}; 00167 00168 hres = create_dispex(ctx, NULL, NULL, &var_disp); 00169 if(FAILED(hres)) 00170 return hres; 00171 00172 hres = create_arguments(ctx, (IDispatch*)_IDispatchEx_(&function->dispex), 00173 dp, ei, caller, &arg_disp); 00174 if(SUCCEEDED(hres)) { 00175 VARIANT var; 00176 00177 V_VT(&var) = VT_DISPATCH; 00178 V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(arg_disp); 00179 hres = jsdisp_propput_name(var_disp, argumentsW, &var, ei, caller); 00180 jsdisp_release(arg_disp); 00181 } 00182 00183 if(SUCCEEDED(hres)) 00184 hres = init_parameters(var_disp, function, dp, ei, caller); 00185 if(FAILED(hres)) { 00186 jsdisp_release(var_disp); 00187 return hres; 00188 } 00189 00190 *ret = var_disp; 00191 return S_OK; 00192 } 00193 00194 static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, DISPPARAMS *dp, 00195 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00196 { 00197 DispatchEx *var_disp; 00198 exec_ctx_t *exec_ctx; 00199 scope_chain_t *scope; 00200 HRESULT hres; 00201 00202 if(!function->source) { 00203 FIXME("no source\n"); 00204 return E_FAIL; 00205 } 00206 00207 hres = create_var_disp(ctx, function, dp, ei, caller, &var_disp); 00208 if(FAILED(hres)) 00209 return hres; 00210 00211 hres = scope_push(function->scope_chain, var_disp, &scope); 00212 if(SUCCEEDED(hres)) { 00213 hres = create_exec_ctx(ctx, this_obj, var_disp, scope, &exec_ctx); 00214 scope_release(scope); 00215 } 00216 jsdisp_release(var_disp); 00217 if(FAILED(hres)) 00218 return hres; 00219 00220 hres = exec_source(exec_ctx, function->parser, function->source, EXECT_FUNCTION, ei, retv); 00221 exec_release(exec_ctx); 00222 00223 return hres; 00224 } 00225 00226 static HRESULT invoke_constructor(script_ctx_t *ctx, FunctionInstance *function, DISPPARAMS *dp, 00227 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00228 { 00229 DispatchEx *this_obj; 00230 VARIANT var; 00231 HRESULT hres; 00232 00233 hres = create_object(ctx, &function->dispex, &this_obj); 00234 if(FAILED(hres)) 00235 return hres; 00236 00237 hres = invoke_source(ctx, function, (IDispatch*)_IDispatchEx_(this_obj), dp, &var, ei, caller); 00238 if(FAILED(hres)) { 00239 jsdisp_release(this_obj); 00240 return hres; 00241 } 00242 00243 V_VT(retv) = VT_DISPATCH; 00244 if(V_VT(&var) == VT_DISPATCH) { 00245 jsdisp_release(this_obj); 00246 V_DISPATCH(retv) = V_DISPATCH(&var); 00247 }else { 00248 VariantClear(&var); 00249 V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(this_obj); 00250 } 00251 return S_OK; 00252 } 00253 00254 static HRESULT invoke_value_proc(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_disp, WORD flags, DISPPARAMS *dp, 00255 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00256 { 00257 vdisp_t vthis; 00258 HRESULT hres; 00259 00260 if(this_disp) 00261 set_disp(&vthis, this_disp); 00262 else if(ctx->host_global) 00263 set_disp(&vthis, ctx->host_global); 00264 else 00265 set_jsdisp(&vthis, ctx->global); 00266 00267 hres = function->value_proc(ctx, &vthis, flags, dp, retv, ei, caller); 00268 00269 vdisp_release(&vthis); 00270 return hres; 00271 } 00272 00273 static HRESULT call_function(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, DISPPARAMS *args, 00274 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00275 { 00276 if(function->value_proc) 00277 return invoke_value_proc(ctx, function, this_obj, DISPATCH_METHOD, args, retv, ei, caller); 00278 00279 return invoke_source(ctx, function, this_obj, args, retv, ei, caller); 00280 } 00281 00282 static HRESULT function_to_string(FunctionInstance *function, BSTR *ret) 00283 { 00284 BSTR str; 00285 00286 static const WCHAR native_prefixW[] = {'\n','f','u','n','c','t','i','o','n',' '}; 00287 static const WCHAR native_suffixW[] = 00288 {'(',')',' ','{','\n',' ',' ',' ',' ','[','n','a','t','i','v','e',' ','c','o','d','e',']','\n','}','\n'}; 00289 00290 if(function->value_proc) { 00291 DWORD name_len; 00292 00293 name_len = strlenW(function->name); 00294 str = SysAllocStringLen(NULL, sizeof(native_prefixW) + name_len*sizeof(WCHAR) + sizeof(native_suffixW)); 00295 if(!str) 00296 return E_OUTOFMEMORY; 00297 00298 memcpy(str, native_prefixW, sizeof(native_prefixW)); 00299 memcpy(str + sizeof(native_prefixW)/sizeof(WCHAR), function->name, name_len*sizeof(WCHAR)); 00300 memcpy(str + sizeof(native_prefixW)/sizeof(WCHAR) + name_len, native_suffixW, sizeof(native_suffixW)); 00301 }else { 00302 str = SysAllocStringLen(function->src_str, function->src_len); 00303 if(!str) 00304 return E_OUTOFMEMORY; 00305 } 00306 00307 *ret = str; 00308 return S_OK; 00309 } 00310 00311 static HRESULT Function_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00312 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 00313 { 00314 FunctionInstance *This = function_from_vdisp(jsthis); 00315 00316 TRACE("%p %d\n", This, This->length); 00317 00318 switch(flags) { 00319 case DISPATCH_PROPERTYGET: 00320 V_VT(retv) = VT_I4; 00321 V_I4(retv) = This->length; 00322 break; 00323 default: 00324 FIXME("unimplemented flags %x\n", flags); 00325 return E_NOTIMPL; 00326 } 00327 00328 return S_OK; 00329 } 00330 00331 static HRESULT Function_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00332 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 00333 { 00334 FunctionInstance *function; 00335 BSTR str; 00336 HRESULT hres; 00337 00338 TRACE("\n"); 00339 00340 if(!(function = function_this(jsthis))) 00341 return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL); 00342 00343 hres = function_to_string(function, &str); 00344 if(FAILED(hres)) 00345 return hres; 00346 00347 if(retv) { 00348 V_VT(retv) = VT_BSTR; 00349 V_BSTR(retv) = str; 00350 }else { 00351 SysFreeString(str); 00352 } 00353 return S_OK; 00354 } 00355 00356 static HRESULT array_to_args(script_ctx_t *ctx, DispatchEx *arg_array, jsexcept_t *ei, IServiceProvider *caller, 00357 DISPPARAMS *args) 00358 { 00359 VARIANT var, *argv; 00360 DWORD length, i; 00361 HRESULT hres; 00362 00363 hres = jsdisp_propget_name(arg_array, lengthW, &var, ei, NULL/*FIXME*/); 00364 if(FAILED(hres)) 00365 return hres; 00366 00367 hres = to_uint32(ctx, &var, ei, &length); 00368 VariantClear(&var); 00369 if(FAILED(hres)) 00370 return hres; 00371 00372 argv = heap_alloc(length * sizeof(VARIANT)); 00373 if(!argv) 00374 return E_OUTOFMEMORY; 00375 00376 for(i=0; i<length; i++) { 00377 hres = jsdisp_get_idx(arg_array, i, argv+i, ei, caller); 00378 if(hres == DISP_E_UNKNOWNNAME) 00379 V_VT(argv+i) = VT_EMPTY; 00380 else if(FAILED(hres)) { 00381 while(i--) 00382 VariantClear(argv+i); 00383 heap_free(argv); 00384 return hres; 00385 } 00386 } 00387 00388 args->cArgs = length; 00389 args->rgvarg = argv; 00390 return S_OK; 00391 } 00392 00393 static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00394 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00395 { 00396 FunctionInstance *function; 00397 DISPPARAMS args = {NULL,NULL,0,0}; 00398 DWORD argc, i; 00399 IDispatch *this_obj = NULL; 00400 HRESULT hres = S_OK; 00401 00402 TRACE("\n"); 00403 00404 if(!(function = function_this(jsthis))) 00405 return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL); 00406 00407 argc = arg_cnt(dp); 00408 if(argc) { 00409 VARIANT *v = get_arg(dp,0); 00410 00411 if(V_VT(v) != VT_EMPTY && V_VT(v) != VT_NULL) { 00412 hres = to_object(ctx, v, &this_obj); 00413 if(FAILED(hres)) 00414 return hres; 00415 } 00416 } 00417 00418 if(argc >= 2) { 00419 DispatchEx *arg_array = NULL; 00420 00421 if(V_VT(get_arg(dp,1)) == VT_DISPATCH) { 00422 arg_array = iface_to_jsdisp((IUnknown*)V_DISPATCH(get_arg(dp,1))); 00423 if(arg_array && 00424 (!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS) )) { 00425 jsdisp_release(arg_array); 00426 arg_array = NULL; 00427 } 00428 } 00429 00430 if(arg_array) { 00431 hres = array_to_args(ctx, arg_array, ei, caller, &args); 00432 jsdisp_release(arg_array); 00433 }else { 00434 FIXME("throw TypeError\n"); 00435 hres = E_FAIL; 00436 } 00437 } 00438 00439 hres = call_function(ctx, function, this_obj, &args, retv, ei, caller); 00440 00441 if(this_obj) 00442 IDispatch_Release(this_obj); 00443 for(i=0; i<args.cArgs; i++) 00444 VariantClear(args.rgvarg+i); 00445 heap_free(args.rgvarg); 00446 return hres; 00447 } 00448 00449 static HRESULT Function_call(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00450 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00451 { 00452 FunctionInstance *function; 00453 DISPPARAMS args = {NULL,NULL,0,0}; 00454 IDispatch *this_obj = NULL; 00455 DWORD argc; 00456 HRESULT hres; 00457 00458 TRACE("\n"); 00459 00460 if(!(function = function_this(jsthis))) 00461 return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL); 00462 00463 argc = arg_cnt(dp); 00464 if(argc) { 00465 VARIANT *v = get_arg(dp,0); 00466 00467 if(V_VT(v) != VT_EMPTY && V_VT(v) != VT_NULL) { 00468 hres = to_object(ctx, v, &this_obj); 00469 if(FAILED(hres)) 00470 return hres; 00471 } 00472 00473 args.cArgs = argc-1; 00474 } 00475 00476 if(args.cArgs) 00477 args.rgvarg = dp->rgvarg + dp->cArgs - args.cArgs-1; 00478 00479 hres = call_function(ctx, function, this_obj, &args, retv, ei, caller); 00480 00481 if(this_obj) 00482 IDispatch_Release(this_obj); 00483 return hres; 00484 } 00485 00486 HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00487 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00488 { 00489 FunctionInstance *function; 00490 00491 TRACE("\n"); 00492 00493 if(!is_vclass(jsthis, JSCLASS_FUNCTION)) { 00494 ERR("dispex is not a function\n"); 00495 return E_FAIL; 00496 } 00497 00498 function = (FunctionInstance*)jsthis->u.jsdisp; 00499 00500 switch(flags) { 00501 case DISPATCH_METHOD: 00502 if(function->value_proc) 00503 return invoke_value_proc(ctx, function, get_this(dp), flags, dp, retv, ei, caller); 00504 00505 return invoke_source(ctx, function, get_this(dp), dp, retv, ei, caller); 00506 00507 case DISPATCH_PROPERTYGET: { 00508 HRESULT hres; 00509 BSTR str; 00510 00511 hres = function_to_string(function, &str); 00512 if(FAILED(hres)) 00513 return hres; 00514 00515 V_VT(retv) = VT_BSTR; 00516 V_BSTR(retv) = str; 00517 break; 00518 } 00519 00520 case DISPATCH_CONSTRUCT: 00521 if(function->value_proc) 00522 return invoke_value_proc(ctx, function, get_this(dp), flags, dp, retv, ei, caller); 00523 00524 return invoke_constructor(ctx, function, dp, retv, ei, caller); 00525 00526 default: 00527 FIXME("not implemented flags %x\n", flags); 00528 return E_NOTIMPL; 00529 } 00530 00531 return S_OK; 00532 } 00533 00534 static void Function_destructor(DispatchEx *dispex) 00535 { 00536 FunctionInstance *This = (FunctionInstance*)dispex; 00537 00538 if(This->parser) 00539 parser_release(This->parser); 00540 if(This->scope_chain) 00541 scope_release(This->scope_chain); 00542 heap_free(This); 00543 } 00544 00545 static const builtin_prop_t Function_props[] = { 00546 {applyW, Function_apply, PROPF_METHOD|2}, 00547 {callW, Function_call, PROPF_METHOD|1}, 00548 {lengthW, Function_length, 0}, 00549 {toStringW, Function_toString, PROPF_METHOD} 00550 }; 00551 00552 static const builtin_info_t Function_info = { 00553 JSCLASS_FUNCTION, 00554 {NULL, Function_value, 0}, 00555 sizeof(Function_props)/sizeof(*Function_props), 00556 Function_props, 00557 Function_destructor, 00558 NULL 00559 }; 00560 00561 static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_info, DWORD flags, 00562 BOOL funcprot, DispatchEx *prototype, FunctionInstance **ret) 00563 { 00564 FunctionInstance *function; 00565 HRESULT hres; 00566 00567 function = heap_alloc_zero(sizeof(FunctionInstance)); 00568 if(!function) 00569 return E_OUTOFMEMORY; 00570 00571 if(funcprot) 00572 hres = init_dispex(&function->dispex, ctx, &Function_info, prototype); 00573 else if(builtin_info) 00574 hres = init_dispex_from_constr(&function->dispex, ctx, builtin_info, ctx->function_constr); 00575 else 00576 hres = init_dispex_from_constr(&function->dispex, ctx, &Function_info, ctx->function_constr); 00577 if(FAILED(hres)) 00578 return hres; 00579 00580 function->flags = flags; 00581 function->length = flags & PROPF_ARGMASK; 00582 00583 *ret = function; 00584 return S_OK; 00585 } 00586 00587 static HRESULT set_prototype(script_ctx_t *ctx, DispatchEx *dispex, DispatchEx *prototype) 00588 { 00589 jsexcept_t jsexcept; 00590 VARIANT var; 00591 00592 V_VT(&var) = VT_DISPATCH; 00593 V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(prototype); 00594 memset(&jsexcept, 0, sizeof(jsexcept)); 00595 00596 return jsdisp_propput_name(dispex, prototypeW, &var, &jsexcept, NULL/*FIXME*/); 00597 } 00598 00599 HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, const WCHAR *name, 00600 const builtin_info_t *builtin_info, DWORD flags, DispatchEx *prototype, DispatchEx **ret) 00601 { 00602 FunctionInstance *function; 00603 HRESULT hres; 00604 00605 hres = create_function(ctx, builtin_info, flags, FALSE, NULL, &function); 00606 if(FAILED(hres)) 00607 return hres; 00608 00609 if(builtin_info) { 00610 VARIANT var; 00611 00612 V_VT(&var) = VT_I4; 00613 V_I4(&var) = function->length; 00614 hres = jsdisp_propput_const(&function->dispex, lengthW, &var); 00615 } 00616 00617 if(SUCCEEDED(hres)) 00618 hres = set_prototype(ctx, &function->dispex, prototype); 00619 if(FAILED(hres)) { 00620 jsdisp_release(&function->dispex); 00621 return hres; 00622 } 00623 00624 function->value_proc = value_proc; 00625 function->name = name; 00626 00627 *ret = &function->dispex; 00628 return S_OK; 00629 } 00630 00631 HRESULT create_source_function(parser_ctx_t *ctx, parameter_t *parameters, source_elements_t *source, 00632 scope_chain_t *scope_chain, const WCHAR *src_str, DWORD src_len, DispatchEx **ret) 00633 { 00634 FunctionInstance *function; 00635 DispatchEx *prototype; 00636 parameter_t *iter; 00637 DWORD length = 0; 00638 HRESULT hres; 00639 00640 hres = create_object(ctx->script, NULL, &prototype); 00641 if(FAILED(hres)) 00642 return hres; 00643 00644 hres = create_function(ctx->script, NULL, PROPF_CONSTR, FALSE, NULL, &function); 00645 if(SUCCEEDED(hres)) { 00646 hres = set_prototype(ctx->script, &function->dispex, prototype); 00647 if(FAILED(hres)) 00648 jsdisp_release(&function->dispex); 00649 } 00650 jsdisp_release(prototype); 00651 if(FAILED(hres)) 00652 return hres; 00653 00654 function->source = source; 00655 function->parameters = parameters; 00656 00657 if(scope_chain) { 00658 scope_addref(scope_chain); 00659 function->scope_chain = scope_chain; 00660 } 00661 00662 parser_addref(ctx); 00663 function->parser = ctx; 00664 00665 for(iter = parameters; iter; iter = iter->next) 00666 length++; 00667 function->length = length; 00668 00669 function->src_str = src_str; 00670 function->src_len = src_len; 00671 00672 *ret = &function->dispex; 00673 return S_OK; 00674 } 00675 00676 static HRESULT construct_function(script_ctx_t *ctx, DISPPARAMS *dp, jsexcept_t *ei, IDispatch **ret) 00677 { 00678 function_expression_t *expr; 00679 WCHAR *str = NULL, *ptr; 00680 DWORD argc, len = 0, l; 00681 parser_ctx_t *parser; 00682 DispatchEx *function; 00683 BSTR *params = NULL; 00684 int i=0, j=0; 00685 HRESULT hres = S_OK; 00686 00687 static const WCHAR function_anonymousW[] = {'f','u','n','c','t','i','o','n',' ','a','n','o','n','y','m','o','u','s','('}; 00688 static const WCHAR function_beginW[] = {')',' ','{','\n'}; 00689 static const WCHAR function_endW[] = {'\n','}',0}; 00690 00691 argc = arg_cnt(dp); 00692 if(argc) { 00693 params = heap_alloc(argc*sizeof(BSTR)); 00694 if(!params) 00695 return E_OUTOFMEMORY; 00696 00697 if(argc > 2) 00698 len = (argc-2)*2; /* separating commas */ 00699 for(i=0; i < argc; i++) { 00700 hres = to_string(ctx, get_arg(dp,i), ei, params+i); 00701 if(FAILED(hres)) 00702 break; 00703 len += SysStringLen(params[i]); 00704 } 00705 } 00706 00707 if(SUCCEEDED(hres)) { 00708 len += (sizeof(function_anonymousW) + sizeof(function_beginW) + sizeof(function_endW)) / sizeof(WCHAR); 00709 str = heap_alloc(len*sizeof(WCHAR)); 00710 if(str) { 00711 memcpy(str, function_anonymousW, sizeof(function_anonymousW)); 00712 ptr = str + sizeof(function_anonymousW)/sizeof(WCHAR); 00713 if(argc > 1) { 00714 while(1) { 00715 l = SysStringLen(params[j]); 00716 memcpy(ptr, params[j], l*sizeof(WCHAR)); 00717 ptr += l; 00718 if(++j == argc-1) 00719 break; 00720 *ptr++ = ','; 00721 *ptr++ = ' '; 00722 } 00723 } 00724 memcpy(ptr, function_beginW, sizeof(function_beginW)); 00725 ptr += sizeof(function_beginW)/sizeof(WCHAR); 00726 if(argc) { 00727 l = SysStringLen(params[argc-1]); 00728 memcpy(ptr, params[argc-1], l*sizeof(WCHAR)); 00729 ptr += l; 00730 } 00731 memcpy(ptr, function_endW, sizeof(function_endW)); 00732 00733 TRACE("%s\n", debugstr_w(str)); 00734 }else { 00735 hres = E_OUTOFMEMORY; 00736 } 00737 } 00738 00739 while(--i >= 0) 00740 SysFreeString(params[i]); 00741 heap_free(params); 00742 if(FAILED(hres)) 00743 return hres; 00744 00745 hres = script_parse(ctx, str, NULL, &parser); 00746 heap_free(str); 00747 if(FAILED(hres)) 00748 return hres; 00749 00750 if(!parser->source || !parser->source->functions || parser->source->functions->next || parser->source->variables) { 00751 ERR("Invalid parser result!\n"); 00752 parser_release(parser); 00753 return E_UNEXPECTED; 00754 } 00755 expr = parser->source->functions->expr; 00756 00757 hres = create_source_function(parser, expr->parameter_list, expr->source_elements, NULL, expr->src_str, 00758 expr->src_len, &function); 00759 parser_release(parser); 00760 if(FAILED(hres)) 00761 return hres; 00762 00763 *ret = (IDispatch*)_IDispatchEx_(function); 00764 return S_OK; 00765 } 00766 00767 static HRESULT FunctionConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00768 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 00769 { 00770 HRESULT hres; 00771 00772 TRACE("\n"); 00773 00774 switch(flags) { 00775 case DISPATCH_CONSTRUCT: { 00776 IDispatch *ret; 00777 00778 hres = construct_function(ctx, dp, ei, &ret); 00779 if(FAILED(hres)) 00780 return hres; 00781 00782 V_VT(retv) = VT_DISPATCH; 00783 V_DISPATCH(retv) = ret; 00784 break; 00785 } 00786 default: 00787 FIXME("unimplemented flags %x\n", flags); 00788 return E_NOTIMPL; 00789 } 00790 00791 return S_OK; 00792 } 00793 00794 static HRESULT FunctionProt_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00795 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 00796 { 00797 FIXME("\n"); 00798 return E_NOTIMPL; 00799 } 00800 00801 HRESULT init_function_constr(script_ctx_t *ctx, DispatchEx *object_prototype) 00802 { 00803 FunctionInstance *prot, *constr; 00804 HRESULT hres; 00805 00806 static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0}; 00807 00808 hres = create_function(ctx, NULL, PROPF_CONSTR, TRUE, object_prototype, &prot); 00809 if(FAILED(hres)) 00810 return hres; 00811 00812 prot->value_proc = FunctionProt_value; 00813 prot->name = prototypeW; 00814 00815 hres = create_function(ctx, NULL, PROPF_CONSTR|1, TRUE, &prot->dispex, &constr); 00816 if(SUCCEEDED(hres)) { 00817 constr->value_proc = FunctionConstr_value; 00818 constr->name = FunctionW; 00819 hres = set_prototype(ctx, &constr->dispex, &prot->dispex); 00820 if(FAILED(hres)) 00821 jsdisp_release(&constr->dispex); 00822 } 00823 jsdisp_release(&prot->dispex); 00824 if(FAILED(hres)) 00825 return hres; 00826 00827 ctx->function_constr = &constr->dispex; 00828 return S_OK; 00829 } Generated on Sun May 27 2012 04:16:28 for ReactOS by
1.7.6.1
|