[PATCH v11 0/3] MR10588: vbscript: Add missing compiler error constants, messages, and todo tests.
Add 13 missing VBSE error code definitions (1006, 1007, 1012, 1015, 1016, 1022, 1029, 1030, 1040, 1050, 1051, 1052, 1058) with string resources and test entries. Fix 6 of the 12 tests by adding error productions for mismatched End keywords in blocks (1012, 1015, 1016, 1022, 1029, 1050). The remaining 6 tests (1006, 1007, 1040, 1052, 1058) are todo_wine pending further parser work. -- v11: vbscript: Return specific errors for unclosed parens, multiple defaults, and default on Property Let/Set. https://gitlab.winehq.org/wine/wine/-/merge_requests/10588
From: Francis De Brabandere <francisdb@gmail.com> Add 13 missing VBSE error code definitions (1006, 1007, 1012, 1015, 1016, 1022, 1029, 1030, 1040, 1050, 1051, 1052, 1058) with their string resources, and 12 todo_wine test entries covering the error codes that can be safely triggered. --- dlls/vbscript/tests/run.c | 101 +++++++++++++++++++++++++++++++++- dlls/vbscript/vbscript.rc | 13 +++++ dlls/vbscript/vbscript_defs.h | 13 +++++ 3 files changed, 125 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index be71769d6de..5f5a82424ef 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -2742,7 +2742,7 @@ static void test_parse_errors(void) static const struct { const WCHAR *src; - unsigned error_line; + int error_line; int error_char; const WCHAR *source_line; HRESULT source_line_hres; @@ -3122,6 +3122,102 @@ static void test_parse_errors(void) L"\x00e9var = 1\n", 0, 0, NULL, S_OK, 1032 + }, + { + /* Expected ')' - error 1006 */ + L"x = (1 + 2\n", + 0, 10, + NULL, S_OK, -1006 + }, + { + /* Expected ']' - error 1007 */ + L"Dim [foo\n", + 0, -8, + NULL, S_OK, -1007 + }, + { + /* Expected 'If' - End With inside If block - error 1012 */ + L"If True Then\n" + " x = 1\n" + "End With\n", + 2, 4, + NULL, S_OK, -1012 + }, + { + /* Expected 'Function' - End Sub inside Function - error 1015 */ + L"Function F()\n" + "End Sub\n", + 1, 4, + NULL, S_OK, -1015 + }, + { + /* Expected 'Sub' - End Function inside Sub - error 1016 */ + L"Sub S()\n" + "End Function\n", + 1, 4, + NULL, S_OK, -1016 + }, + { + /* Expected 'Select' - End If inside Select block - error 1022 */ + L"Select Case 1\n" + " Case 1\n" + "End If\n", + 2, 4, + NULL, S_OK, -1022 + }, + { + /* Expected 'With' - End Sub inside With block - error 1029 */ + L"With CreateObject(\"Scripting.Dictionary\")\n" + "End Sub\n", + 1, 4, + NULL, S_OK, -1029 + }, + { + /* Invalid 'for' loop control variable - error 1040 */ + L"Dim x\n" + "For x.y = 1 To 3\n" + "Next\n", + 1, -8, + NULL, S_OK, -1040 + }, + { + /* Invalid 'for each' loop control variable - error 1040 */ + L"Dim x\n" + "For Each x.y In Array(1)\n" + "Next\n", + 1, -13, + NULL, S_OK, -1040 + }, + { + /* Expected 'Property' - End Sub inside Property Get - error 1050 */ + L"Class C\n" + " Property Get P()\n" + " End Sub\n" + "End Class\n", + 2, 6, + NULL, S_OK, -1050 + }, + { + /* Multiple default members - error 1052 */ + L"Class C\n" + " Public Default Function F()\n" + " F = 1\n" + " End Function\n" + " Public Default Function G()\n" + " G = 2\n" + " End Function\n" + "End Class\n", + -4, -17, + NULL, S_OK, -1052 + }, + { + /* Default only on Property Get - error 1058 */ + L"Class C\n" + " Public Default Property Let P(v)\n" + " End Property\n" + "End Class\n", + -1, -26, + NULL, S_OK, -1058 } }; HRESULT hres; @@ -3139,7 +3235,8 @@ static void test_parse_errors(void) ok(hres == SCRIPT_E_REPORTED, "[%u] script returned: %08lx\n", i, hres); CHECK_CALLED(OnScriptError); - ok(error_line == invalid_scripts[i].error_line, "[%u] error line %lu expected %u\n", + todo_wine_if(invalid_scripts[i].error_line < 0) + ok(error_line == abs(invalid_scripts[i].error_line), "[%u] error line %lu expected %d\n", i, error_line, invalid_scripts[i].error_line); todo_wine_if(invalid_scripts[i].error_char < 0) ok(error_char == abs(invalid_scripts[i].error_char), "[%u] error char %ld expected %d\n", diff --git a/dlls/vbscript/vbscript.rc b/dlls/vbscript/vbscript.rc index 5e3adddc789..4602ed520e7 100644 --- a/dlls/vbscript/vbscript.rc +++ b/dlls/vbscript/vbscript.rc @@ -64,24 +64,33 @@ STRINGTABLE VBSE_UNQUALIFIED_REFERENCE "Invalid or unqualified reference" VBSE_SYNTAX_ERROR "Syntax error" VBSE_EXPECTED_LPAREN "Expected '('" + VBSE_EXPECTED_RPAREN "Expected ')'" + VBSE_EXPECTED_RBRACKET "Expected ']'" VBSE_EXPECTED_IDENTIFIER "Expected identifier" VBSE_EXPECTED_ASSIGN "Expected '='" + VBSE_EXPECTED_IF "Expected 'If'" VBSE_EXPECTED_TO "Expected 'To'" VBSE_EXPECTED_END "Expected 'End'" + VBSE_EXPECTED_FUNCTION "Expected 'Function'" + VBSE_EXPECTED_SUB "Expected 'Sub'" VBSE_EXPECTED_THEN "Expected 'Then'" VBSE_EXPECTED_WEND "Expected 'Wend'" VBSE_EXPECTED_LOOP "Expected 'Loop'" VBSE_EXPECTED_NEXT "Expected 'Next'" VBSE_EXPECTED_CASE "Expected 'Case'" + VBSE_EXPECTED_SELECT "Expected 'Select'" VBSE_EXPECTED_STATEMENT "Expected statement" VBSE_EXPECTED_END_OF_STATEMENT "Expected end of statement" VBSE_EXPECTED_INTEGER_CONSTANT "Expected integer constant" VBSE_EXPECTED_WHILE_UNTIL_EOS "Expected 'While', 'Until' or end of statement" + VBSE_EXPECTED_WITH "Expected 'With'" + VBSE_IDENTIFIER_TOO_LONG "Identifier too long" VBSE_INVALID_NUMBER "Invalid number" VBSE_INVALID_CHAR "Invalid character" 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" @@ -90,10 +99,14 @@ STRINGTABLE VBSE_EXPECTED_CLASS "Expected 'Class'" VBSE_MUST_BE_INSIDE_CLASS "Must be defined inside a Class" VBSE_EXPECTED_LET_SET_GET "Expected Let or Set or Get in property declaration" + VBSE_EXPECTED_PROPERTY "Expected 'Property'" + VBSE_PROPERTY_ARG_COUNT_MISMATCH "Number of arguments must be consistent across properties specification" + VBSE_MULTIPLE_DEFAULT_MEMBERS "Cannot have multiple default property/method in a Class" VBSE_CLASS_INIT_NO_ARGS "Class initialize or terminate do not have arguments" VBSE_PROPERTY_LET_SET_NEEDS_ARG "Property set or let must have at least one argument" VBSE_UNEXPECTED_NEXT "Unexpected 'Next'" VBSE_DEFAULT_MUST_BE_PUBLIC "'Default' specification must also specify 'Public'" + VBSE_DEFAULT_ONLY_ON_PROPERTY_GET "'Default' specification can only be on Property Get" VBS_COMPILE_ERROR "Microsoft VBScript compilation error" VBS_RUNTIME_ERROR "Microsoft VBScript runtime error" diff --git a/dlls/vbscript/vbscript_defs.h b/dlls/vbscript/vbscript_defs.h index 0dc7b677517..1efd900c170 100644 --- a/dlls/vbscript/vbscript_defs.h +++ b/dlls/vbscript/vbscript_defs.h @@ -275,24 +275,33 @@ #define VBSE_UNQUALIFIED_REFERENCE 505 #define VBSE_SYNTAX_ERROR 1002 #define VBSE_EXPECTED_LPAREN 1005 +#define VBSE_EXPECTED_RPAREN 1006 +#define VBSE_EXPECTED_RBRACKET 1007 #define VBSE_EXPECTED_IDENTIFIER 1010 #define VBSE_EXPECTED_ASSIGN 1011 +#define VBSE_EXPECTED_IF 1012 #define VBSE_EXPECTED_TO 1013 #define VBSE_EXPECTED_END 1014 +#define VBSE_EXPECTED_FUNCTION 1015 +#define VBSE_EXPECTED_SUB 1016 #define VBSE_EXPECTED_THEN 1017 #define VBSE_EXPECTED_WEND 1018 #define VBSE_EXPECTED_LOOP 1019 #define VBSE_EXPECTED_NEXT 1020 #define VBSE_EXPECTED_CASE 1021 +#define VBSE_EXPECTED_SELECT 1022 #define VBSE_EXPECTED_STATEMENT 1024 #define VBSE_EXPECTED_END_OF_STATEMENT 1025 #define VBSE_EXPECTED_INTEGER_CONSTANT 1026 #define VBSE_EXPECTED_WHILE_UNTIL_EOS 1028 +#define VBSE_EXPECTED_WITH 1029 +#define VBSE_IDENTIFIER_TOO_LONG 1030 #define VBSE_INVALID_NUMBER 1031 #define VBSE_INVALID_CHAR 1032 #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 @@ -301,10 +310,14 @@ #define VBSE_EXPECTED_CLASS 1047 #define VBSE_MUST_BE_INSIDE_CLASS 1048 #define VBSE_EXPECTED_LET_SET_GET 1049 +#define VBSE_EXPECTED_PROPERTY 1050 +#define VBSE_PROPERTY_ARG_COUNT_MISMATCH 1051 +#define VBSE_MULTIPLE_DEFAULT_MEMBERS 1052 #define VBSE_CLASS_INIT_NO_ARGS 1053 #define VBSE_PROPERTY_LET_SET_NEEDS_ARG 1054 #define VBSE_UNEXPECTED_NEXT 1055 #define VBSE_DEFAULT_MUST_BE_PUBLIC 1057 +#define VBSE_DEFAULT_ONLY_ON_PROPERTY_GET 1058 #define VBS_COMPILE_ERROR 4096 #define VBS_RUNTIME_ERROR 4097 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10588
From: Francis De Brabandere <francisdb@gmail.com> Add error productions to detect wrong End keywords inside If, Select, With, Sub, Function, and Property blocks. For example, 'End With' inside an If block now returns error 1012 "Expected 'If'" instead of the generic 1002 "Syntax error". --- dlls/vbscript/parser.y | 20 ++++++++++++++++++++ dlls/vbscript/tests/run.c | 12 ++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index f4b573e2d15..ab4f6250aa1 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -249,8 +249,12 @@ SimpleStatement { $$ = new_foreach_statement(ctx, @$, $3, $5, $7); } | tSELECT tCASE Expression StSep CaseClausules tEND tSELECT { $$ = new_select_statement(ctx, @$, $3, $5); } + | tSELECT tCASE Expression StSep CaseClausules tEND error + { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_SELECT); YYABORT; } | tWITH Expression StSep StatementsNl_opt tEND tWITH { $$ = new_with_statement(ctx, @$, $2, $4); } + | tWITH Expression StSep StatementsNl_opt tEND error + { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_WITH); YYABORT; } MemberExpression : Identifier { $$ = new_member_expression(ctx, NULL, $1); CHECK_ERROR; } @@ -319,6 +323,8 @@ IfStatement { $$ = new_if_statement(ctx, @$, $2, $4, NULL, $6); CHECK_ERROR; } | tIF Expression tTHEN Statement tELSE EndIf_opt { $$ = new_if_statement(ctx, @$, $2, $4, NULL, NULL); CHECK_ERROR; } + | tIF Expression tTHEN tNL StSep_opt StatementsNl_opt ElseIfs_opt Else_opt tEND error + { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_IF); YYABORT; } EndIf_opt : /* empty */ @@ -500,16 +506,30 @@ PropertyDecl { $$ = new_function_decl(ctx, $4, FUNC_PROPLET, @2, $1, $6, $9); CHECK_ERROR; } | Storage_opt tPROPERTY tSET Identifier '(' ArgumentDeclList ')' StSep BodyStatements tEND tPROPERTY { $$ = new_function_decl(ctx, $4, FUNC_PROPSET, @2, $1, $6, $9); CHECK_ERROR; } + | Storage_opt tPROPERTY tGET Identifier ArgumentsDecl_opt StSep BodyStatements tEND error + { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_PROPERTY); YYABORT; } + | Storage_opt tPROPERTY tLET Identifier '(' ArgumentDeclList ')' StSep BodyStatements tEND error + { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_PROPERTY); YYABORT; } + | Storage_opt tPROPERTY tSET Identifier '(' ArgumentDeclList ')' StSep BodyStatements tEND error + { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_PROPERTY); YYABORT; } FunctionDecl : Storage_opt tSUB Identifier StSep BodyStatements tEND tSUB { $$ = new_function_decl(ctx, $3, FUNC_SUB, @2, $1, NULL, $5); CHECK_ERROR; } | Storage_opt tSUB Identifier ArgumentsDecl Nl_opt BodyStatements tEND tSUB { $$ = new_function_decl(ctx, $3, FUNC_SUB, @2, $1, $4, $6); CHECK_ERROR; } + | Storage_opt tSUB Identifier StSep BodyStatements tEND error + { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_SUB); YYABORT; } + | Storage_opt tSUB Identifier ArgumentsDecl Nl_opt BodyStatements tEND error + { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_SUB); YYABORT; } | Storage_opt tFUNCTION Identifier StSep BodyStatements tEND tFUNCTION { $$ = new_function_decl(ctx, $3, FUNC_FUNCTION, @2, $1, NULL, $5); CHECK_ERROR; } | Storage_opt tFUNCTION Identifier ArgumentsDecl Nl_opt BodyStatements tEND tFUNCTION { $$ = new_function_decl(ctx, $3, FUNC_FUNCTION, @2, $1, $4, $6); CHECK_ERROR; } + | Storage_opt tFUNCTION Identifier StSep BodyStatements tEND error + { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_FUNCTION); YYABORT; } + | Storage_opt tFUNCTION Identifier ArgumentsDecl Nl_opt BodyStatements tEND error + { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_FUNCTION); YYABORT; } Storage_opt : /* empty*/ { $$ = 0; } diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 5f5a82424ef..b5aebf619f2 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -3141,21 +3141,21 @@ static void test_parse_errors(void) " x = 1\n" "End With\n", 2, 4, - NULL, S_OK, -1012 + NULL, S_OK, 1012 }, { /* Expected 'Function' - End Sub inside Function - error 1015 */ L"Function F()\n" "End Sub\n", 1, 4, - NULL, S_OK, -1015 + NULL, S_OK, 1015 }, { /* Expected 'Sub' - End Function inside Sub - error 1016 */ L"Sub S()\n" "End Function\n", 1, 4, - NULL, S_OK, -1016 + NULL, S_OK, 1016 }, { /* Expected 'Select' - End If inside Select block - error 1022 */ @@ -3163,14 +3163,14 @@ static void test_parse_errors(void) " Case 1\n" "End If\n", 2, 4, - NULL, S_OK, -1022 + NULL, S_OK, 1022 }, { /* Expected 'With' - End Sub inside With block - error 1029 */ L"With CreateObject(\"Scripting.Dictionary\")\n" "End Sub\n", 1, 4, - NULL, S_OK, -1029 + NULL, S_OK, 1029 }, { /* Invalid 'for' loop control variable - error 1040 */ @@ -3195,7 +3195,7 @@ static void test_parse_errors(void) " End Sub\n" "End Class\n", 2, 6, - NULL, S_OK, -1050 + NULL, S_OK, 1050 }, { /* Multiple default members - error 1052 */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10588
From: Francis De Brabandere <francisdb@gmail.com> Return error 1006 "Expected ')'" for unclosed parentheses in expressions, error 1052 for multiple Default members in a class, and error 1058 for Default on Property Let/Set instead of Property Get. Set error locations for 1052 and 1058 to match Windows behavior. --- dlls/vbscript/parser.y | 15 +++++++++++---- dlls/vbscript/tests/run.c | 10 +++++----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index ab4f6250aa1..c166ba68790 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -483,6 +483,7 @@ IntegerValue PrimaryExpression : tEXPRLBRACKET Expression ')' { $$ = new_unary_expression(ctx, EXPR_BRACKETS, $2); } + | tEXPRLBRACKET Expression error { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_RPAREN); YYABORT; } | tME { $$ = new_expression(ctx, EXPR_ME, 0); CHECK_ERROR; } ClassDeclaration @@ -503,9 +504,11 @@ PropertyDecl : Storage_opt tPROPERTY tGET Identifier ArgumentsDecl_opt StSep BodyStatements tEND tPROPERTY { $$ = new_function_decl(ctx, $4, FUNC_PROPGET, @2, $1, $5, $7); CHECK_ERROR; } | Storage_opt tPROPERTY tLET Identifier '(' ArgumentDeclList ')' StSep BodyStatements tEND tPROPERTY - { $$ = new_function_decl(ctx, $4, FUNC_PROPLET, @2, $1, $6, $9); CHECK_ERROR; } + { if($1 & STORAGE_IS_DEFAULT) { ctx->error_loc = @3; ctx->hres = MAKE_VBSERROR(VBSE_DEFAULT_ONLY_ON_PROPERTY_GET); YYABORT; } + $$ = new_function_decl(ctx, $4, FUNC_PROPLET, @2, $1, $6, $9); CHECK_ERROR; } | Storage_opt tPROPERTY tSET Identifier '(' ArgumentDeclList ')' StSep BodyStatements tEND tPROPERTY - { $$ = new_function_decl(ctx, $4, FUNC_PROPSET, @2, $1, $6, $9); CHECK_ERROR; } + { if($1 & STORAGE_IS_DEFAULT) { ctx->error_loc = @3; ctx->hres = MAKE_VBSERROR(VBSE_DEFAULT_ONLY_ON_PROPERTY_GET); YYABORT; } + $$ = new_function_decl(ctx, $4, FUNC_PROPSET, @2, $1, $6, $9); CHECK_ERROR; } | Storage_opt tPROPERTY tGET Identifier ArgumentsDecl_opt StSep BodyStatements tEND error { ctx->hres = MAKE_VBSERROR(VBSE_EXPECTED_PROPERTY); YYABORT; } | Storage_opt tPROPERTY tLET Identifier '(' ArgumentDeclList ')' StSep BodyStatements tEND error @@ -1118,8 +1121,7 @@ static function_decl_t *new_function_decl(parser_ctx_t *ctx, const WCHAR *name, if(type == FUNC_PROPGET || type == FUNC_FUNCTION || type == FUNC_SUB) { is_default = TRUE; }else { - FIXME("Invalid default property\n"); - ctx->hres = E_FAIL; + ctx->hres = MAKE_VBSERROR(VBSE_DEFAULT_ONLY_ON_PROPERTY_GET); return NULL; } } @@ -1171,6 +1173,11 @@ static class_decl_t *add_class_function(parser_ctx_t *ctx, class_decl_t *class_d function_decl_t *iter; for(iter = class_decl->funcs; iter; iter = iter->next) { + if(decl->is_default && iter->is_default) { + ctx->error_loc = iter->loc; + ctx->hres = MAKE_VBSERROR(VBSE_MULTIPLE_DEFAULT_MEMBERS); + return NULL; + } if(!wcsicmp(iter->name, decl->name)) { if(decl->type == FUNC_SUB || decl->type == FUNC_FUNCTION) { ctx->hres = MAKE_VBSERROR(VBSE_NAME_REDEFINED); diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index b5aebf619f2..c3783a460db 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -3127,7 +3127,7 @@ static void test_parse_errors(void) /* Expected ')' - error 1006 */ L"x = (1 + 2\n", 0, 10, - NULL, S_OK, -1006 + NULL, S_OK, 1006 }, { /* Expected ']' - error 1007 */ @@ -3207,8 +3207,8 @@ static void test_parse_errors(void) " G = 2\n" " End Function\n" "End Class\n", - -4, -17, - NULL, S_OK, -1052 + 4, 17, + NULL, S_OK, 1052 }, { /* Default only on Property Get - error 1058 */ @@ -3216,8 +3216,8 @@ static void test_parse_errors(void) " Public Default Property Let P(v)\n" " End Property\n" "End Class\n", - -1, -26, - NULL, S_OK, -1058 + 1, 26, + NULL, S_OK, 1058 } }; HRESULT hres; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10588
participants (2)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb)