ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

function.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.