jscript: Alias arguments properties to real values.
This commit is contained in:
parent
4821b06ed1
commit
6b56c65f8d
|
@ -39,7 +39,8 @@ typedef enum {
|
|||
PROP_JSVAL,
|
||||
PROP_BUILTIN,
|
||||
PROP_PROTREF,
|
||||
PROP_DELETED
|
||||
PROP_DELETED,
|
||||
PROP_IDX
|
||||
} prop_type_t;
|
||||
|
||||
struct _dispex_prop_t {
|
||||
|
@ -52,6 +53,7 @@ struct _dispex_prop_t {
|
|||
jsval_t val;
|
||||
const builtin_prop_t *p;
|
||||
DWORD ref;
|
||||
unsigned idx;
|
||||
} u;
|
||||
|
||||
int bucket_head;
|
||||
|
@ -219,6 +221,23 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
if(This->builtin_info->idx_length) {
|
||||
const WCHAR *ptr;
|
||||
unsigned idx = 0;
|
||||
|
||||
for(ptr = name; isdigitW(*ptr) && idx < 0x10000; ptr++)
|
||||
idx = idx*10 + (*ptr-'0');
|
||||
if(!*ptr && idx < This->builtin_info->idx_length(This)) {
|
||||
prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? 0 : PROPF_CONST);
|
||||
if(!prop)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
prop->u.idx = idx;
|
||||
*ret = prop;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
*ret = NULL;
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -383,10 +402,14 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t
|
|||
|
||||
return disp_call_value(This->ctx, get_object(prop->u.val), jsthis, flags, argc, argv, r);
|
||||
}
|
||||
default:
|
||||
ERR("type %d\n", prop->type);
|
||||
case PROP_IDX:
|
||||
FIXME("Invoking PROP_IDX not yet supported\n");
|
||||
return E_NOTIMPL;
|
||||
case PROP_DELETED:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
|
@ -423,6 +446,9 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, DISPPARAMS *dp,
|
|||
case PROP_JSVAL:
|
||||
hres = jsval_copy(prop->u.val, r);
|
||||
break;
|
||||
case PROP_IDX:
|
||||
hres = This->builtin_info->idx_get(This, prop->u.idx, r);
|
||||
break;
|
||||
default:
|
||||
ERR("type %d\n", prop->type);
|
||||
return E_FAIL;
|
||||
|
@ -463,6 +489,8 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServi
|
|||
case PROP_JSVAL:
|
||||
jsval_release(prop->u.val);
|
||||
break;
|
||||
case PROP_IDX:
|
||||
return This->builtin_info->idx_put(This, prop->u.idx, val);
|
||||
default:
|
||||
ERR("type %d\n", prop->type);
|
||||
return E_FAIL;
|
||||
|
@ -479,7 +507,6 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServi
|
|||
if(This->builtin_info->on_put)
|
||||
This->builtin_info->on_put(This, prop->name);
|
||||
|
||||
TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,12 @@ typedef struct {
|
|||
jsdisp_t *arguments;
|
||||
} FunctionInstance;
|
||||
|
||||
typedef struct {
|
||||
jsdisp_t jsdisp;
|
||||
FunctionInstance *function;
|
||||
jsdisp_t *var_obj;
|
||||
} ArgumentsInstance;
|
||||
|
||||
static inline FunctionInstance *function_from_vdisp(vdisp_t *vdisp)
|
||||
{
|
||||
return (FunctionInstance*)vdisp->u.jsdisp;
|
||||
|
@ -77,61 +83,102 @@ static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static void Arguments_destructor(jsdisp_t *jsdisp)
|
||||
{
|
||||
ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
|
||||
|
||||
jsdisp_release(&arguments->function->dispex);
|
||||
jsdisp_release(arguments->var_obj);
|
||||
heap_free(arguments);
|
||||
}
|
||||
|
||||
static unsigned Arguments_idx_length(jsdisp_t *jsdisp)
|
||||
{
|
||||
ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
|
||||
return arguments->function->length;
|
||||
}
|
||||
|
||||
static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *res)
|
||||
{
|
||||
ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
|
||||
|
||||
TRACE("%p[%u]\n", arguments, idx);
|
||||
|
||||
/* FIXME: Accessing by name won't work for duplicated argument names */
|
||||
return jsdisp_propget_name(arguments->var_obj, arguments->function->func_code->params[idx], res);
|
||||
}
|
||||
|
||||
static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val)
|
||||
{
|
||||
ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp;
|
||||
|
||||
TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val));
|
||||
|
||||
/* FIXME: Accessing by name won't work for duplicated argument names */
|
||||
return jsdisp_propput_name(arguments->var_obj, arguments->function->func_code->params[idx], val);
|
||||
}
|
||||
|
||||
static const builtin_info_t Arguments_info = {
|
||||
JSCLASS_ARGUMENTS,
|
||||
{NULL, Arguments_value, 0},
|
||||
0, NULL,
|
||||
Arguments_destructor,
|
||||
NULL,
|
||||
NULL
|
||||
Arguments_idx_length,
|
||||
Arguments_idx_get,
|
||||
Arguments_idx_put
|
||||
};
|
||||
|
||||
static HRESULT create_arguments(script_ctx_t *ctx, IDispatch *calee, unsigned argc, jsval_t *argv, jsdisp_t **ret)
|
||||
static HRESULT create_arguments(script_ctx_t *ctx, FunctionInstance *calee, jsdisp_t *var_obj,
|
||||
unsigned argc, jsval_t *argv, jsdisp_t **ret)
|
||||
{
|
||||
jsdisp_t *args;
|
||||
DWORD i;
|
||||
ArgumentsInstance *args;
|
||||
unsigned i;
|
||||
HRESULT hres;
|
||||
|
||||
static const WCHAR caleeW[] = {'c','a','l','l','e','e',0};
|
||||
|
||||
args = heap_alloc_zero(sizeof(jsdisp_t));
|
||||
args = heap_alloc_zero(sizeof(*args));
|
||||
if(!args)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
hres = init_dispex_from_constr(args, ctx, &Arguments_info, ctx->object_constr);
|
||||
hres = init_dispex_from_constr(&args->jsdisp, ctx, &Arguments_info, ctx->object_constr);
|
||||
if(FAILED(hres)) {
|
||||
heap_free(args);
|
||||
return hres;
|
||||
}
|
||||
|
||||
for(i=0; i < argc; i++) {
|
||||
jsdisp_addref(&calee->dispex);
|
||||
args->function = calee;
|
||||
args->var_obj = jsdisp_addref(var_obj);
|
||||
|
||||
/* Store unnamed arguments directly in arguments object */
|
||||
for(i = calee->length; i < argc; i++) {
|
||||
WCHAR buf[12];
|
||||
|
||||
static const WCHAR formatW[] = {'%','d',0};
|
||||
|
||||
sprintfW(buf, formatW, i);
|
||||
hres = jsdisp_propput_dontenum(args, buf, argv[i]);
|
||||
hres = jsdisp_propput_dontenum(&args->jsdisp, buf, argv[i]);
|
||||
if(FAILED(hres))
|
||||
break;
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hres)) {
|
||||
hres = jsdisp_propput_dontenum(args, lengthW, jsval_number(argc));
|
||||
|
||||
hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(argc));
|
||||
if(SUCCEEDED(hres))
|
||||
hres = jsdisp_propput_dontenum(args, caleeW, jsval_disp(calee));
|
||||
hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&calee->dispex)));
|
||||
}
|
||||
|
||||
if(FAILED(hres)) {
|
||||
jsdisp_release(args);
|
||||
jsdisp_release(&args->jsdisp);
|
||||
return hres;
|
||||
}
|
||||
|
||||
*ret = args;
|
||||
*ret = &args->jsdisp;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, jsdisp_t *arg_disp,
|
||||
unsigned argc, jsval_t *argv, jsdisp_t **ret)
|
||||
static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, unsigned argc, jsval_t *argv, jsdisp_t **ret)
|
||||
{
|
||||
jsdisp_t *var_disp;
|
||||
HRESULT hres;
|
||||
|
@ -140,9 +187,7 @@ static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, js
|
|||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = jsdisp_propput_name(var_disp, argumentsW, jsval_obj(arg_disp));
|
||||
if(SUCCEEDED(hres))
|
||||
hres = init_parameters(var_disp, function, argc, argv);
|
||||
hres = init_parameters(var_disp, function, argc, argv);
|
||||
if(FAILED(hres)) {
|
||||
jsdisp_release(var_disp);
|
||||
return hres;
|
||||
|
@ -165,20 +210,23 @@ static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDis
|
|||
return E_FAIL;
|
||||
}
|
||||
|
||||
hres = create_arguments(ctx, to_disp(&function->dispex), argc, argv, &arg_disp);
|
||||
hres = create_var_disp(ctx, function, argc, argv, &var_disp);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = create_var_disp(ctx, function, arg_disp, argc, argv, &var_disp);
|
||||
hres = create_arguments(ctx, function, var_disp, argc, argv, &arg_disp);
|
||||
if(FAILED(hres)) {
|
||||
jsdisp_release(arg_disp);
|
||||
jsdisp_release(var_disp);
|
||||
return hres;
|
||||
}
|
||||
|
||||
hres = scope_push(function->scope_chain, var_disp, to_disp(var_disp), &scope);
|
||||
hres = jsdisp_propput_name(var_disp, argumentsW, jsval_obj(arg_disp));
|
||||
if(SUCCEEDED(hres)) {
|
||||
hres = create_exec_ctx(ctx, this_obj, var_disp, scope, FALSE, &exec_ctx);
|
||||
scope_release(scope);
|
||||
hres = scope_push(function->scope_chain, var_disp, to_disp(var_disp), &scope);
|
||||
if(SUCCEEDED(hres)) {
|
||||
hres = create_exec_ctx(ctx, this_obj, var_disp, scope, FALSE, &exec_ctx);
|
||||
scope_release(scope);
|
||||
}
|
||||
}
|
||||
jsdisp_release(var_disp);
|
||||
if(SUCCEEDED(hres)) {
|
||||
|
|
|
@ -200,6 +200,9 @@ typedef struct {
|
|||
const builtin_prop_t *props;
|
||||
void (*destructor)(jsdisp_t*);
|
||||
void (*on_put)(jsdisp_t*,const WCHAR*);
|
||||
unsigned (*idx_length)(jsdisp_t*);
|
||||
HRESULT (*idx_get)(jsdisp_t*,unsigned,jsval_t*);
|
||||
HRESULT (*idx_put)(jsdisp_t*,unsigned,jsval_t);
|
||||
} builtin_info_t;
|
||||
|
||||
struct jsdisp_t {
|
||||
|
|
|
@ -74,6 +74,15 @@ function testFunc1(x, y) {
|
|||
ok(arguments.callee === testFunc1, "arguments.calee !== testFunc1");
|
||||
ok(testFunc1.arguments === arguments, "testFunc1.arguments = " + testFunc1.arguments);
|
||||
|
||||
x = false;
|
||||
ok(arguments[0] === false, "arguments[0] is not false");
|
||||
arguments[1] = "x";
|
||||
ok(y === "x", "y = " + y);
|
||||
ok(arguments[1] === "x", "arguments[1] = " + arguments[1]);
|
||||
|
||||
ok(arguments["0x0"] === undefined, "arguments['0x0'] = " + arguments["0x0"]);
|
||||
ok(arguments["x"] === undefined, "arguments['x'] = " + arguments["x"]);
|
||||
|
||||
ok(this === test, "this !== test");
|
||||
eval('ok(this === test, "this !== test");');
|
||||
|
||||
|
|
Loading…
Reference in New Issue