From: Francis De Brabandere <francisdb@gmail.com> Windows VBScript rejects member expressions (e.g. x.y) as For/For Each loop control variables with error 1040. Accept MemberExpression in the parser rules and check for obj_expr to report the proper error instead of a generic syntax error. --- dlls/vbscript/parser.y | 13 +++++++++---- dlls/vbscript/tests/run.c | 12 ++++++++++++ dlls/vbscript/vbscript.rc | 1 + dlls/vbscript/vbscript_defs.h | 1 + 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index c1a5b944268..a0eff59e31b 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -241,10 +241,15 @@ SimpleStatement | tON tERROR tRESUME tNEXT { $$ = new_onerror_statement(ctx, @$, TRUE); CHECK_ERROR; } | tON tERROR tGOTO '0' { $$ = new_onerror_statement(ctx, @$, FALSE); CHECK_ERROR; } | tCONST ConstDeclList { $$ = new_const_statement(ctx, @$, $2); CHECK_ERROR; } - | tFOR Identifier '=' Expression tTO Expression Step_opt StSep StatementsNl_opt tNEXT - { $$ = new_forto_statement(ctx, @$, $2, $4, $6, $7, $9); CHECK_ERROR; } - | tFOR tEACH Identifier tIN Expression StSep StatementsNl_opt tNEXT - { $$ = new_foreach_statement(ctx, @$, $3, $5, $7); } + | tFOR MemberExpression '=' Expression tTO Expression Step_opt StSep StatementsNl_opt tNEXT + { if($2->obj_expr) { ctx->error_loc = @3; + ctx->hres = MAKE_VBSERROR(VBSE_INVALID_FOR_CONTROL); CHECK_ERROR; } + $$ = new_forto_statement(ctx, @$, $2->identifier, $4, $6, $7, $9); + CHECK_ERROR; } + | tFOR tEACH MemberExpression tIN Expression StSep StatementsNl_opt tNEXT + { if($3->obj_expr) { ctx->error_loc = @4; + ctx->hres = MAKE_VBSERROR(VBSE_INVALID_FOR_CONTROL); CHECK_ERROR; } + $$ = new_foreach_statement(ctx, @$, $3->identifier, $5, $7); } | tSELECT tCASE Expression StSep CaseClausules tEND tSELECT { $$ = new_select_statement(ctx, @$, $3, $5); } | tWITH Expression StSep StatementsNl_opt tEND tWITH diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index d3aebff098a..bbda5183b61 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -3025,6 +3025,18 @@ static void test_parse_errors(void) L"Class C\nDefault Private Function f()\nf = 1\nEnd Function\nEnd Class\n", 1, 0, NULL, S_OK, 1057 + }, + { + /* Invalid 'for' loop control variable (member expression) - error 1040 */ + L"Dim x\nFor x.y = 1 To 3\nNext\n", + 1, 8, + NULL, S_OK, 1040 + }, + { + /* Invalid 'for each' loop control variable (member expression) - error 1040 */ + L"Dim x\nFor Each x.y In Array(1)\nNext\n", + 1, 13, + NULL, S_OK, 1040 } }; HRESULT hres; diff --git a/dlls/vbscript/vbscript.rc b/dlls/vbscript/vbscript.rc index a0f7381bcf0..49c3e8059a1 100644 --- a/dlls/vbscript/vbscript.rc +++ b/dlls/vbscript/vbscript.rc @@ -79,6 +79,7 @@ STRINGTABLE VBSE_UNTERMINATED_STRING "Unterminated string constant" VBSE_LOOP_WITHOUT_DO "'loop' without 'do'" VBSE_INVALID_EXIT "Invalid 'exit' statement" + VBSE_INVALID_FOR_CONTROL "Invalid 'for' loop control variable" VBSE_NAME_REDEFINED "Name redefined" VBSE_MUST_BE_FIRST_STATEMENT "Must be first statement on the line" VBSE_CANNOT_USE_PARENS_CALLING_SUB "Cannot use parentheses when calling a Sub" diff --git a/dlls/vbscript/vbscript_defs.h b/dlls/vbscript/vbscript_defs.h index 06d3b8990fb..7a104b3c342 100644 --- a/dlls/vbscript/vbscript_defs.h +++ b/dlls/vbscript/vbscript_defs.h @@ -290,6 +290,7 @@ #define VBSE_UNTERMINATED_STRING 1033 #define VBSE_LOOP_WITHOUT_DO 1038 #define VBSE_INVALID_EXIT 1039 +#define VBSE_INVALID_FOR_CONTROL 1040 #define VBSE_NAME_REDEFINED 1041 #define VBSE_MUST_BE_FIRST_STATEMENT 1042 #define VBSE_CANNOT_USE_PARENS_CALLING_SUB 1044 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10484