[PATCH v3 0/1] MR10362: vbscript: Support chained call syntax like dict.Keys()(i).
Treat '(' after tEMPTYBRACKETS as an argument list opener in the lexer, so that expressions like GetArr()(0) or dict.Keys()(i) parse correctly. Also dereference VT_BYREF|VT_VARIANT results in vcall so chained indexing on call results works at runtime. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58051 This includes some of the work done in !10308, preferably that one is merged first. -- v3: vbscript: Support chained call syntax like dict.Keys()(i). https://gitlab.winehq.org/wine/wine/-/merge_requests/10362
From: Francis De Brabandere <francisdb@gmail.com> Treat '(' after tEMPTYBRACKETS as an argument list opener in the lexer, so that expressions like GetArr()(0) or dict.Keys()(i) parse correctly. Also dereference VT_BYREF|VT_VARIANT results in vcall so chained indexing on call results works at runtime. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58051 --- dlls/vbscript/interp.c | 9 ++++++++- dlls/vbscript/lex.c | 3 ++- dlls/vbscript/tests/lang.vbs | 5 +++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 79225af27b9..0090d8723f5 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -708,13 +708,20 @@ static HRESULT interp_icallv(exec_ctx_t *ctx) static HRESULT interp_vcall(exec_ctx_t *ctx) { const unsigned arg_cnt = ctx->instr->arg1.uint; - VARIANT res, *v; + VARIANT res = {0}, *v; HRESULT hres; TRACE("\n"); v = stack_pop(ctx); hres = variant_call(ctx, v, arg_cnt, &res); + if(SUCCEEDED(hres) && V_VT(&res) == (VT_BYREF|VT_VARIANT)) { + VARIANT tmp; + V_VT(&tmp) = VT_EMPTY; + hres = VariantCopyInd(&tmp, &res); + if(SUCCEEDED(hres)) + res = tmp; + } VariantClear(v); if(FAILED(hres)) return hres; diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 75838ac586a..d595bda7fa0 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -465,7 +465,8 @@ static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx) * Parser can't predict if bracket is part of argument expression or an argument * in call expression. We predict it here instead. */ - if(ctx->last_token == tIdentifier || ctx->last_token == ')' || ctx->last_token == tME) + if(ctx->last_token == tIdentifier || ctx->last_token == ')' || ctx->last_token == tME + || ctx->last_token == tEMPTYBRACKETS) return '('; return tEXPRLBRACKET; case '"': diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 49889609aa9..916b51c742b 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -1666,6 +1666,11 @@ ok arr2(1,2) = 2, "arr2(1,2) = " & arr2(1,2) x = Array(Array(3)) call ok(x(0)(0) = 3, "x(0)(0) = " & x(0)(0)) +Function GetABC() + GetABC = Array("a", "b", "c") +End Function +call ok(GetABC()(0) = "a", "GetABC()(0) = " & GetABC()(0)) + function seta0(arr) arr(0) = 2 seta0 = 1 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10362
Jacek Caban (@jacek) commented about dlls/vbscript/interp.c:
const unsigned arg_cnt = ctx->instr->arg1.uint; - VARIANT res, *v; + VARIANT res = {0}, *v; HRESULT hres;
TRACE("\n");
v = stack_pop(ctx); hres = variant_call(ctx, v, arg_cnt, &res); + if(SUCCEEDED(hres) && V_VT(&res) == (VT_BYREF|VT_VARIANT)) { + VARIANT tmp; + V_VT(&tmp) = VT_EMPTY; + hres = VariantCopyInd(&tmp, &res); + if(SUCCEEDED(hres)) + res = tmp; + }
While it seems that we should indeed do that in this case, there are more cases with the same problem. Could we do that in `variant_call`, or even in `disp_call`, instead? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10362#note_133463
participants (3)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb) -
Jacek Caban (@jacek)