From: Francis De Brabandere <francisdb@gmail.com> When a name is defined twice (Const/Const, Dim/Const, Const/Dim, Dim/Dim, Sub vs Const/Dim, Class vs Const/Dim/Function), Windows returns VBScript error 1041 ("Name redefined"). Wine was returning E_FAIL. Store the identifier location in const_decl_t and dim_decl_t so errors point to the duplicate name, not the keyword. --- dlls/vbscript/compile.c | 29 +++++++++++++++++------------ dlls/vbscript/interp.c | 4 ++-- dlls/vbscript/parse.h | 2 ++ dlls/vbscript/parser.y | 24 +++++++++++++----------- dlls/vbscript/tests/run.c | 27 +++++++++++++++++++++++++++ dlls/vbscript/vbscript_defs.h | 1 + 6 files changed, 62 insertions(+), 25 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 345e3b5291b..067eec33bc3 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1138,8 +1138,9 @@ static HRESULT compile_dim_statement(compile_ctx_t *ctx, dim_statement_t *stat) while(1) { if(lookup_dim_decls(ctx, dim_decl->name) || lookup_args_name(ctx, dim_decl->name) || lookup_const_decls(ctx, dim_decl->name, FALSE)) { - FIXME("dim %s name redefined\n", debugstr_w(dim_decl->name)); - return E_FAIL; + ctx->loc = dim_decl->loc; + WARN("dim %s name redefined\n", debugstr_w(dim_decl->name)); + return MAKE_VBSERROR(VBSE_NAME_REDEFINED); } ctx->func->var_cnt++; @@ -1201,8 +1202,8 @@ static HRESULT compile_const_statement(compile_ctx_t *ctx, const_statement_t *st if(!lookup_const_decls(ctx, decl->name, FALSE)) { if(lookup_args_name(ctx, decl->name) || lookup_dim_decls(ctx, decl->name)) { - FIXME("%s redefined\n", debugstr_w(decl->name)); - return E_FAIL; + WARN("%s redefined\n", debugstr_w(decl->name)); + return MAKE_VBSERROR(VBSE_NAME_REDEFINED); } } @@ -1373,12 +1374,16 @@ static HRESULT collect_const_decls(compile_ctx_t *ctx, statement_t *stat) for(decl = const_stat->decls; decl; decl = decl->next) { const_decl_t *new_decl; - if(lookup_const_decls(ctx, decl->name, FALSE)) - break; /* already collected */ + if(lookup_const_decls(ctx, decl->name, FALSE)) { + ctx->loc = decl->loc; + WARN("%s: const redefined\n", debugstr_w(decl->name)); + return MAKE_VBSERROR(VBSE_NAME_REDEFINED); + } if(lookup_args_name(ctx, decl->name) || lookup_dim_decls(ctx, decl->name)) { - FIXME("%s redefined\n", debugstr_w(decl->name)); - return E_FAIL; + ctx->loc = decl->loc; + WARN("%s redefined\n", debugstr_w(decl->name)); + return MAKE_VBSERROR(VBSE_NAME_REDEFINED); } new_decl = compiler_alloc(ctx->code, sizeof(*new_decl)); @@ -1712,8 +1717,8 @@ static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, functi HRESULT hres; if(lookup_dim_decls(ctx, decl->name) || lookup_const_decls(ctx, decl->name, FALSE)) { - FIXME("%s: redefinition\n", debugstr_w(decl->name)); - return E_FAIL; + WARN("%s: redefinition\n", debugstr_w(decl->name)); + return MAKE_VBSERROR(VBSE_NAME_REDEFINED); } func = compiler_alloc(ctx->code, sizeof(*func)); @@ -1835,8 +1840,8 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) if(lookup_dim_decls(ctx, class_decl->name) || lookup_funcs_name(ctx, class_decl->name) || lookup_const_decls(ctx, class_decl->name, FALSE) || lookup_class_name(ctx, class_decl->name)) { - FIXME("%s: redefinition\n", debugstr_w(class_decl->name)); - return E_FAIL; + WARN("%s: redefinition\n", debugstr_w(class_decl->name)); + return MAKE_VBSERROR(VBSE_NAME_REDEFINED); } class_desc = compiler_alloc_zero(ctx->code, sizeof(*class_desc)); diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 00ef7d93eb6..5c729825d34 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1065,8 +1065,8 @@ static HRESULT interp_const(exec_ctx_t *ctx) return hres; if(ref.type != REF_NONE) { - FIXME("%s already defined\n", debugstr_w(arg)); - return E_FAIL; + WARN("%s already defined\n", debugstr_w(arg)); + return MAKE_VBSERROR(VBSE_NAME_REDEFINED); } hres = stack_assume_val(ctx, 0); diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h index 71fc713ea9c..c5a2457f709 100644 --- a/dlls/vbscript/parse.h +++ b/dlls/vbscript/parse.h @@ -161,6 +161,7 @@ typedef struct _dim_list_t { typedef struct _dim_decl_t { const WCHAR *name; + unsigned loc; BOOL is_array; BOOL is_public; /* Used only for class members. */ dim_list_t *dims; @@ -257,6 +258,7 @@ typedef struct { typedef struct _const_decl_t { const WCHAR *name; + unsigned loc; expression_t *value_expr; struct _const_decl_t *next; } const_decl_t; diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index 4977358b333..afd274f8260 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -62,13 +62,13 @@ static statement_t *new_const_statement(parser_ctx_t*,unsigned,const_decl_t*); static statement_t *new_select_statement(parser_ctx_t*,unsigned,expression_t*,case_clausule_t*); static statement_t *new_with_statement(parser_ctx_t*,unsigned,expression_t*,statement_t*); -static dim_decl_t *new_dim_decl(parser_ctx_t*,const WCHAR*,BOOL,dim_list_t*); +static dim_decl_t *new_dim_decl(parser_ctx_t*,unsigned,const WCHAR*,BOOL,dim_list_t*); static dim_list_t *new_dim(parser_ctx_t*,unsigned,dim_list_t*); static redim_decl_t *new_redim_decl(parser_ctx_t*,const WCHAR*,expression_t*); static elseif_decl_t *new_elseif_decl(parser_ctx_t*,unsigned,expression_t*,statement_t*); static function_decl_t *new_function_decl(parser_ctx_t*,const WCHAR*,function_type_t,unsigned,arg_decl_t*,statement_t*); static arg_decl_t *new_argument_decl(parser_ctx_t*,const WCHAR*,BOOL); -static const_decl_t *new_const_decl(parser_ctx_t*,const WCHAR*,expression_t*); +static const_decl_t *new_const_decl(parser_ctx_t*,unsigned,const WCHAR*,expression_t*); static case_clausule_t *new_case_clausule(parser_ctx_t*,expression_t*,statement_t*,case_clausule_t*); static class_decl_t *new_class_decl(parser_ctx_t*); @@ -262,9 +262,9 @@ MemberDeclList | MemberDecl ',' MemberDeclList { $1->next = $3; $$ = $1; } MemberDecl - : MemberIdentifier { $$ = new_dim_decl(ctx, $1, FALSE, NULL); CHECK_ERROR; } - | MemberIdentifier '(' DimList ')' { $$ = new_dim_decl(ctx, $1, TRUE, $3); CHECK_ERROR; } - | MemberIdentifier tEMPTYBRACKETS { $$ = new_dim_decl(ctx, $1, TRUE, NULL); CHECK_ERROR; } + : MemberIdentifier { $$ = new_dim_decl(ctx, @1, $1, FALSE, NULL); CHECK_ERROR; } + | MemberIdentifier '(' DimList ')' { $$ = new_dim_decl(ctx, @1, $1, TRUE, $3); CHECK_ERROR; } + | MemberIdentifier tEMPTYBRACKETS { $$ = new_dim_decl(ctx, @1, $1, TRUE, NULL); CHECK_ERROR; } ReDimDecl : tIdentifier '(' ArgumentList ')' { $$ = new_redim_decl(ctx, $1, $3); CHECK_ERROR; } @@ -278,9 +278,9 @@ DimDeclList | DimDecl ',' DimDeclList { $1->next = $3; $$ = $1; } DimDecl - : Identifier { $$ = new_dim_decl(ctx, $1, FALSE, NULL); CHECK_ERROR; } - | Identifier '(' DimList ')' { $$ = new_dim_decl(ctx, $1, TRUE, $3); CHECK_ERROR; } - | Identifier tEMPTYBRACKETS { $$ = new_dim_decl(ctx, $1, TRUE, NULL); CHECK_ERROR; } + : Identifier { $$ = new_dim_decl(ctx, @1, $1, FALSE, NULL); CHECK_ERROR; } + | Identifier '(' DimList ')' { $$ = new_dim_decl(ctx, @1, $1, TRUE, $3); CHECK_ERROR; } + | Identifier tEMPTYBRACKETS { $$ = new_dim_decl(ctx, @1, $1, TRUE, NULL); CHECK_ERROR; } DimList : IntegerValue { $$ = new_dim(ctx, $1, NULL); } @@ -291,7 +291,7 @@ ConstDeclList | ConstDecl ',' ConstDeclList { $1->next = $3; $$ = $1; } ConstDecl - : Identifier '=' ConstExpression { $$ = new_const_decl(ctx, $1, $3); CHECK_ERROR; } + : Identifier '=' ConstExpression { $$ = new_const_decl(ctx, @1, $1, $3); CHECK_ERROR; } ConstExpression : LiteralExpression { $$ = $1; } @@ -863,7 +863,7 @@ static statement_t *new_set_statement(parser_ctx_t *ctx, unsigned loc, expressio return &stat->stat; } -static dim_decl_t *new_dim_decl(parser_ctx_t *ctx, const WCHAR *name, BOOL is_array, dim_list_t *dims) +static dim_decl_t *new_dim_decl(parser_ctx_t *ctx, unsigned loc, const WCHAR *name, BOOL is_array, dim_list_t *dims) { dim_decl_t *decl; @@ -872,6 +872,7 @@ static dim_decl_t *new_dim_decl(parser_ctx_t *ctx, const WCHAR *name, BOOL is_ar return NULL; decl->name = name; + decl->loc = loc; decl->is_array = is_array; decl->dims = dims; decl->next = NULL; @@ -1184,7 +1185,7 @@ static class_decl_t *add_dim_prop(parser_ctx_t *ctx, class_decl_t *class_decl, d return class_decl; } -static const_decl_t *new_const_decl(parser_ctx_t *ctx, const WCHAR *name, expression_t *expr) +static const_decl_t *new_const_decl(parser_ctx_t *ctx, unsigned loc, const WCHAR *name, expression_t *expr) { const_decl_t *decl; @@ -1193,6 +1194,7 @@ static const_decl_t *new_const_decl(parser_ctx_t *ctx, const WCHAR *name, expres return NULL; decl->name = name; + decl->loc = loc; decl->value_expr = expr; decl->next = NULL; return decl; diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 8e8feb60b1d..0e0fd45d350 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -2863,6 +2863,33 @@ static void test_parse_errors(void) L"x = &H100000001\n", 0, 4, L"x = &H100000001", S_OK + }, + { + /* Const redefined */ + L"Const X = 1\n" + "Const X = 2\n", + 1, 6, + L"Const X = 2", S_OK + }, + { + /* Const redefined on same statement */ + L"Const C = 1, C = 2\n", + 0, 13, + L"Const C = 1, C = 2", S_OK + }, + { + /* Dim after Const with same name */ + L"Const D = 1\n" + "Dim D\n", + 1, 4, + L"Dim D", S_OK + }, + { + /* Const after Dim with same name */ + L"Dim E\n" + "Const E = 1\n", + 0, 4, + L"Dim E", S_OK } }; HRESULT hres; diff --git a/dlls/vbscript/vbscript_defs.h b/dlls/vbscript/vbscript_defs.h index e0e9d1cac94..0462e0e2cee 100644 --- a/dlls/vbscript/vbscript_defs.h +++ b/dlls/vbscript/vbscript_defs.h @@ -270,6 +270,7 @@ #define VBSE_INVALID_TYPELIB_VARIABLE 458 #define VBSE_SERVER_NOT_FOUND 462 #define VBSE_UNQUALIFIED_REFERENCE 505 +#define VBSE_NAME_REDEFINED 1041 #define VBS_COMPILE_ERROR 4096 #define VBS_RUNTIME_ERROR 4097 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10464