From 82cace0f0e47fd8a716057fe9509d340a131c84b Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Fri, 7 Mar 2014 14:27:12 +0100 Subject: [PATCH] vbscipt: Added beginning support for arrays as class members. --- dlls/vbscript/compile.c | 69 ++++++++++++++++++++++++++++++-------------- dlls/vbscript/parse.h | 9 ++---- dlls/vbscript/parser.y | 22 ++++++-------- dlls/vbscript/tests/lang.vbs | 23 +++++++++++++++ dlls/vbscript/vbdisp.c | 56 ++++++++++++++++++++++++++++++----- dlls/vbscript/vbscript.h | 16 ++++++---- 6 files changed, 141 insertions(+), 54 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index ea227878270..48853e9d259 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1210,6 +1210,28 @@ static void resolve_labels(compile_ctx_t *ctx, unsigned off) ctx->labels_cnt = 0; } +static HRESULT fill_array_desc(compile_ctx_t *ctx, dim_decl_t *dim_decl, array_desc_t *array_desc) +{ + unsigned dim_cnt = 0, i; + dim_list_t *iter; + + for(iter = dim_decl->dims; iter; iter = iter->next) + dim_cnt++; + + array_desc->bounds = compiler_alloc(ctx->code, dim_cnt * sizeof(SAFEARRAYBOUND)); + if(!array_desc->bounds) + return E_OUTOFMEMORY; + + array_desc->dim_cnt = dim_cnt; + + for(iter = dim_decl->dims, i=0; iter; iter = iter->next, i++) { + array_desc->bounds[i].cElements = iter->val+1; + array_desc->bounds[i].lLbound = 0; + } + + return S_OK; +} + static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *func) { HRESULT hres; @@ -1304,35 +1326,19 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f } if(func->array_cnt) { - unsigned dim_cnt, array_id = 0; + unsigned array_id = 0; dim_decl_t *dim_decl; - dim_list_t *iter; func->array_descs = compiler_alloc(ctx->code, func->array_cnt * sizeof(array_desc_t)); if(!func->array_descs) return E_OUTOFMEMORY; for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) { - if(!dim_decl->is_array) - continue; - - dim_cnt = 0; - for(iter = dim_decl->dims; iter; iter = iter->next) - dim_cnt++; - - func->array_descs[array_id].bounds = compiler_alloc(ctx->code, dim_cnt * sizeof(SAFEARRAYBOUND)); - if(!func->array_descs[array_id].bounds) - return E_OUTOFMEMORY; - - func->array_descs[array_id].dim_cnt = dim_cnt; - - dim_cnt = 0; - for(iter = dim_decl->dims; iter; iter = iter->next) { - func->array_descs[array_id].bounds[dim_cnt].cElements = iter->val+1; - func->array_descs[array_id].bounds[dim_cnt++].lLbound = 0; + if(dim_decl->is_array) { + hres = fill_array_desc(ctx, dim_decl, func->array_descs + array_id++); + if(FAILED(hres)) + return hres; } - - array_id++; } assert(array_id == func->array_cnt); @@ -1475,8 +1481,8 @@ static BOOL lookup_class_funcs(class_desc_t *class_desc, const WCHAR *name) static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) { function_decl_t *func_decl, *func_prop_decl; - class_prop_decl_t *prop_decl; class_desc_t *class_desc; + dim_decl_t *prop_decl; unsigned i; HRESULT hres; @@ -1560,6 +1566,25 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) return E_OUTOFMEMORY; class_desc->props[i].is_public = prop_decl->is_public; + + if(prop_decl->is_array) { + class_desc->props[i].is_array = TRUE; + class_desc->array_cnt++; + } + } + + if(class_desc->array_cnt) { + class_desc->array_descs = compiler_alloc(ctx->code, class_desc->array_cnt*sizeof(*class_desc->array_descs)); + if(!class_desc->array_descs) + return E_OUTOFMEMORY; + + for(prop_decl = class_decl->props, i=0; prop_decl; prop_decl = prop_decl->next) { + if(prop_decl->is_array) { + hres = fill_array_desc(ctx, prop_decl, class_desc->array_descs + i++); + if(FAILED(hres)) + return hres; + } + } } class_desc->next = ctx->classes; diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h index 4b9781436b3..2a497038b4b 100644 --- a/dlls/vbscript/parse.h +++ b/dlls/vbscript/parse.h @@ -146,6 +146,7 @@ typedef struct _dim_list_t { typedef struct _dim_decl_t { const WCHAR *name; BOOL is_array; + BOOL is_public; /* Used only for class members. */ dim_list_t *dims; struct _dim_decl_t *next; } dim_decl_t; @@ -176,16 +177,10 @@ typedef struct { function_decl_t *func_decl; } function_statement_t; -typedef struct _class_prop_decl_t { - BOOL is_public; - const WCHAR *name; - struct _class_prop_decl_t *next; -} class_prop_decl_t; - typedef struct _class_decl_t { const WCHAR *name; function_decl_t *funcs; - class_prop_decl_t *props; + dim_decl_t *props; struct _class_decl_t *next; } class_decl_t; diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index 6e1eb9542fa..3004c3b7ba1 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -67,7 +67,7 @@ static case_clausule_t *new_case_clausule(parser_ctx_t*,expression_t*,statement_ static class_decl_t *new_class_decl(parser_ctx_t*); static class_decl_t *add_class_function(parser_ctx_t*,class_decl_t*,function_decl_t*); -static class_decl_t *add_variant_prop(parser_ctx_t*,class_decl_t*,const WCHAR*,unsigned); +static class_decl_t *add_dim_prop(parser_ctx_t*,class_decl_t*,dim_decl_t*,unsigned); static statement_t *link_statements(statement_t*,statement_t*); @@ -396,7 +396,10 @@ ClassDeclaration ClassBody : /* empty */ { $$ = new_class_decl(ctx); } | FunctionDecl tNL ClassBody { $$ = add_class_function(ctx, $3, $1); CHECK_ERROR; } - | Storage tIdentifier tNL ClassBody { $$ = add_variant_prop(ctx, $4, $2, $1); CHECK_ERROR; } + /* FIXME: We should use DimDecl here to support arrays, but that conflicts with PropertyDecl. */ + | Storage tIdentifier tNL ClassBody { dim_decl_t *dim_decl = new_dim_decl(ctx, $2, FALSE, NULL); CHECK_ERROR; + $$ = add_dim_prop(ctx, $4, dim_decl, $1); CHECK_ERROR; } + | tDIM DimDecl tNL ClassBody { $$ = add_dim_prop(ctx, $4, $2, 0); CHECK_ERROR; } | PropertyDecl tNL ClassBody { $$ = add_class_function(ctx, $3, $1); CHECK_ERROR; } PropertyDecl @@ -891,24 +894,17 @@ static class_decl_t *add_class_function(parser_ctx_t *ctx, class_decl_t *class_d return class_decl; } -static class_decl_t *add_variant_prop(parser_ctx_t *ctx, class_decl_t *class_decl, const WCHAR *identifier, unsigned storage_flags) +static class_decl_t *add_dim_prop(parser_ctx_t *ctx, class_decl_t *class_decl, dim_decl_t *dim_decl, unsigned storage_flags) { - class_prop_decl_t *prop; - if(storage_flags & STORAGE_IS_DEFAULT) { FIXME("variant prop van't be default value\n"); ctx->hres = E_FAIL; return NULL; } - prop = parser_alloc(ctx, sizeof(*prop)); - if(!prop) - return NULL; - - prop->name = identifier; - prop->is_public = !(storage_flags & STORAGE_IS_PRIVATE); - prop->next = class_decl->props; - class_decl->props = prop; + dim_decl->is_public = !(storage_flags & STORAGE_IS_PRIVATE); + dim_decl->next = class_decl->props; + class_decl->props = dim_decl; return class_decl; } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 06d02845381..5d2b77456a6 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -814,6 +814,9 @@ Class TestClass Public Sub Class_Initialize publicProp2 = 2 privateProp = true + 'todo_wine Call ok(getVT(privateProp) = "VT_BOOL*", "getVT(privateProp) = " & getVT(privateProp)) + 'todo_wine Call ok(getVT(publicProp2) = "VT_I2*", "getVT(publicProp2) = " & getVT(publicProp2)) + Call ok(getVT(Me.publicProp2) = "VT_I2", "getVT(Me.publicProp2) = " & getVT(Me.publicProp2)) End Sub End Class @@ -830,6 +833,7 @@ Call obj.publicFunction() Call ok(getVT(obj.publicProp) = "VT_EMPTY", "getVT(obj.publicProp) = " & getVT(obj.publicProp)) obj.publicProp = 3 +Call ok(getVT(obj.publicProp) = "VT_I2", "getVT(obj.publicProp) = " & getVT(obj.publicProp)) Call ok(obj.publicProp = 3, "obj.publicProp = " & obj.publicProp) obj.publicProp() = 3 @@ -1044,4 +1048,23 @@ next x=1 Call ok(forarr(x) = 2, "forarr(x) = " & forarr(x)) +Class ArrClass + Dim classarr(3) + Dim classnoarr() + Dim var + + Private Sub Class_Initialize + 'todo_wine Call ok(getVT(classarr) = "VT_ARRAY|VT_BYREF|VT_VARIANT*", "getVT(classarr) = " & getVT(classarr)) + 'todo_wine Call testArray(-1, classnoarr) + 'classarr(0) = 1 + 'classarr(1) = 2 + 'classarr(2) = 3 + 'classarr(3) = 4 + End Sub +End Class + +Set obj = new ArrClass +'todo_wine Call ok(getVT(obj.classarr) = "VT_ARRAY|VT_VARIANT", "getVT(obj.classarr) = " & getVT(obj.classarr)) +'todo_wine Call ok(obj.classarr(1) = 2, "obj.classarr(1) = " & obj.classarr(1)) + reportSuccess() diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index f0751633d24..351fcf804ab 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -121,6 +121,11 @@ static HRESULT invoke_variant_prop(VARIANT *v, WORD flags, DISPPARAMS *dp, VARIA return DISP_E_PARAMNOTOPTIONAL; } + if(arg_cnt(dp)) { + FIXME("Arguments not supported\n"); + return E_NOTIMPL; + } + if(res) V_VT(res) = VT_EMPTY; @@ -239,6 +244,13 @@ static void clean_props(vbdisp_t *This) if(!This->desc) return; + for(i=0; i < This->desc->array_cnt; i++) { + if(This->arrays[i]) { + SafeArrayDestroy(This->arrays[i]); + This->arrays[i] = NULL; + } + } + for(i=0; i < This->desc->prop_cnt; i++) VariantClear(This->props+i); } @@ -291,6 +303,7 @@ static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) if(!ref && run_terminator(This)) { clean_props(This); list_remove(&This->entry); + heap_free(This->arrays); heap_free(This); } @@ -505,6 +518,7 @@ static inline vbdisp_t *unsafe_impl_from_IDispatch(IDispatch *iface) HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret) { vbdisp_t *vbdisp; + HRESULT hres = S_OK; vbdisp = heap_alloc_zero( FIELD_OFFSET( vbdisp_t, props[desc->prop_cnt] )); if(!vbdisp) @@ -516,16 +530,44 @@ HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret) list_add_tail(&desc->ctx->objects, &vbdisp->entry); - if(desc->class_initialize_id) { - DISPPARAMS dp = {0}; - HRESULT hres; + if(desc->array_cnt) { + vbdisp->arrays = heap_alloc_zero(desc->array_cnt * sizeof(*vbdisp->arrays)); + if(vbdisp->arrays) { + unsigned i, j; + + for(i=0; i < desc->array_cnt; i++) { + if(!desc->array_descs[i].dim_cnt) + continue; + vbdisp->arrays[i] = SafeArrayCreate(VT_VARIANT, desc->array_descs[i].dim_cnt, desc->array_descs[i].bounds); + if(!vbdisp->arrays[i]) { + hres = E_OUTOFMEMORY; + break; + } + } + + if(SUCCEEDED(hres)) { + for(i=0, j=0; i < desc->prop_cnt; i++) { + if(desc->props[i].is_array) { + V_VT(vbdisp->props+i) = VT_ARRAY|VT_BYREF|VT_VARIANT; + V_ARRAYREF(vbdisp->props+i) = vbdisp->arrays + j++; + } + } + } + }else { + hres = E_OUTOFMEMORY; + } + } + + if(SUCCEEDED(hres) && desc->class_initialize_id) { + DISPPARAMS dp = {0}; hres = exec_script(desc->ctx, desc->funcs[desc->class_initialize_id].entries[VBDISP_CALLGET], (IDispatch*)&vbdisp->IDispatchEx_iface, &dp, NULL); - if(FAILED(hres)) { - IDispatchEx_Release(&vbdisp->IDispatchEx_iface); - return hres; - } + } + + if(FAILED(hres)) { + IDispatchEx_Release(&vbdisp->IDispatchEx_iface); + return hres; } *ret = vbdisp; diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index a96d0b10be2..051d37ac9bc 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -68,13 +68,20 @@ typedef enum { } vbdisp_invoke_type_t; typedef struct { + unsigned dim_cnt; + SAFEARRAYBOUND *bounds; +} array_desc_t; + +typedef struct { BOOL is_public; + BOOL is_array; const WCHAR *name; } vbdisp_prop_desc_t; typedef struct { const WCHAR *name; BOOL is_public; + BOOL is_array; function_t *entries[VBDISP_ANY]; } vbdisp_funcprop_desc_t; @@ -101,6 +108,9 @@ typedef struct _class_desc_t { unsigned prop_cnt; vbdisp_prop_desc_t *props; + unsigned array_cnt; + array_desc_t *array_descs; + unsigned builtin_prop_cnt; const builtin_prop_t *builtin_props; ITypeInfo *typeinfo; @@ -117,6 +127,7 @@ struct _vbdisp_t { struct list entry; const class_desc_t *desc; + SAFEARRAY **arrays; VARIANT props[1]; }; @@ -302,11 +313,6 @@ typedef struct { const WCHAR *name; } var_desc_t; -typedef struct { - unsigned dim_cnt; - SAFEARRAYBOUND *bounds; -} array_desc_t; - struct _function_t { function_type_t type; const WCHAR *name; -- 2.11.4.GIT