From: Francis De Brabandere <francisdb@gmail.com> VBScript allows square brackets to quote identifiers containing spaces, special characters, or reserved words. --- dlls/vbscript/lex.c | 30 +++++++++++++++++++++++++ dlls/vbscript/tests/lang.vbs | 41 +++++++++++++++++++++++++++++++++++ dlls/vbscript/tests/run.c | 12 ++++++++++ dlls/vbscript/vbscript.rc | 1 + dlls/vbscript/vbscript_defs.h | 1 + 5 files changed, 85 insertions(+) diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 5f177529460..81cc67e037b 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -410,6 +410,34 @@ static int comment_line(parser_ctx_t *ctx) return tNL; } +static int parse_bracket_identifier(parser_ctx_t *ctx, const WCHAR **ret) +{ + const WCHAR *start = ++ctx->ptr; + WCHAR *str; + int len; + + while(ctx->ptr < ctx->end && *ctx->ptr != ']' && *ctx->ptr != '\n' && *ctx->ptr != '\r') + ctx->ptr++; + + if(ctx->ptr >= ctx->end || *ctx->ptr != ']') + return lex_error(ctx, MAKE_VBSERROR(VBSE_EXPECTED_RBRACKET)); + + len = ctx->ptr - start; + ctx->ptr++; /* skip ']' */ + + if(len > MAX_IDENTIFIER_LENGTH) + return lex_error(ctx, MAKE_VBSERROR(VBSE_IDENTIFIER_TOO_LONG)); + + str = parser_alloc(ctx, (len+1)*sizeof(WCHAR)); + if(!str) + return 0; + + memcpy(str, start, len*sizeof(WCHAR)); + str[len] = 0; + *ret = str; + return tIdentifier; +} + static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx) { WCHAR c; @@ -500,6 +528,8 @@ static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx) || ctx->last_token == tEMPTYBRACKETS) return '('; return tEXPRLBRACKET; + case '[': + return parse_bracket_identifier(ctx, lval); case '"': return parse_string_literal(ctx, lval); case '#': diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 613d6cb42fa..f74979cb109 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -278,6 +278,47 @@ Dim aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 42 Call ok(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 42, "255-char identifier should work") +' Bracketed identifiers +Dim [my var] +[my var] = 42 +Call ok([my var] = 42, "[my var] = " & [my var]) + +Dim [hello world!] +[hello world!] = "works" +Call ok([hello world!] = "works", "[hello world!] = " & [hello world!]) + +Dim [] +[] = "empty" +Call ok([] = "empty", "[] = " & []) + +Dim [ ] +[ ] = "spaces" +Call ok([ ] = "spaces", "[ ] = " & [ ]) + +Dim [dim] +[dim] = 99 +Call ok([dim] = 99, "[dim] = " & [dim]) + +Class BracketTestObj + Public [my property] + Public Sub Class_Initialize + [my property] = "init" + End Sub +End Class + +Dim bracketObj +Set bracketObj = New BracketTestObj +bracketObj.[my property] = "updated" +Call ok(bracketObj.[my property] = "updated", "bracketObj.[my property] = " & bracketObj.[my property]) + +Dim [loop var] +Dim bracketTotal : bracketTotal = 0 +For [loop var] = 1 To 3 + bracketTotal = bracketTotal + [loop var] +Next +Call ok(bracketTotal = 6, "For [loop var] total = " & bracketTotal) + +' Chained call syntax Class ChainedCallTarget Public Function Ret() Set Ret = Me diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index ccd65490f64..337481ff51c 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -3212,6 +3212,18 @@ static void test_parse_errors(void) L"Dim aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", 0, 260, NULL, S_OK, 1030 + }, + { + /* Nested square brackets */ + L"Dim [[nested]]\n", + 0, 13, + NULL, S_OK, 1032 + }, + { + /* Unclosed square bracket */ + L"Dim [unclosed\n", + 0, 13, + NULL, S_OK, 1007 } }; HRESULT hres; diff --git a/dlls/vbscript/vbscript.rc b/dlls/vbscript/vbscript.rc index 98a8d0af1c5..bdb71c86cbd 100644 --- a/dlls/vbscript/vbscript.rc +++ b/dlls/vbscript/vbscript.rc @@ -64,6 +64,7 @@ STRINGTABLE VBSE_UNQUALIFIED_REFERENCE "Invalid or unqualified reference" VBSE_SYNTAX_ERROR "Syntax error" VBSE_EXPECTED_LPAREN "Expected '('" + VBSE_EXPECTED_RBRACKET "Expected ']'" VBSE_EXPECTED_RPAREN "Expected ')'" VBSE_EXPECTED_IDENTIFIER "Expected identifier" VBSE_EXPECTED_ASSIGN "Expected '='" diff --git a/dlls/vbscript/vbscript_defs.h b/dlls/vbscript/vbscript_defs.h index 3edcc79dbb1..1bcc1d8da67 100644 --- a/dlls/vbscript/vbscript_defs.h +++ b/dlls/vbscript/vbscript_defs.h @@ -276,6 +276,7 @@ #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 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10579