[PATCH v8 0/1] MR10302: vbscript: Allow Const to be used before its declaration.
Pre-collect all Const declarations by walking the statement tree before compiling, matching native behavior where constants are visible throughout their enclosing scope. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56931 -- v8: vbscript: Allow Const to be used before its declaration. https://gitlab.winehq.org/wine/wine/-/merge_requests/10302
From: Francis De Brabandere <francisdb@gmail.com> Pre-collect all Const declarations by walking the statement tree before compiling, matching native behavior where constants are visible throughout their enclosing scope. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56931 --- dlls/vbscript/compile.c | 121 +++++++++++++++++++++++++++++++++-- dlls/vbscript/tests/lang.vbs | 7 ++ dlls/vbscript/tests/run.c | 15 +++++ 3 files changed, 137 insertions(+), 6 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index baddc51d7e4..a3fedc950a1 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1199,10 +1199,11 @@ static HRESULT compile_const_statement(compile_ctx_t *ctx, const_statement_t *st do { decl = next_decl; - if(lookup_const_decls(ctx, decl->name, FALSE) || lookup_args_name(ctx, decl->name) - || lookup_dim_decls(ctx, decl->name)) { - FIXME("%s redefined\n", debugstr_w(decl->name)); - return E_FAIL; + 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; + } } if(ctx->func->type == FUNC_GLOBAL) { @@ -1221,8 +1222,10 @@ static HRESULT compile_const_statement(compile_ctx_t *ctx, const_statement_t *st } next_decl = decl->next; - decl->next = ctx->const_decls; - ctx->const_decls = decl; + if(!lookup_const_decls(ctx, decl->name, FALSE)) { + decl->next = ctx->const_decls; + ctx->const_decls = decl; + } } while(next_decl); return S_OK; @@ -1357,6 +1360,107 @@ static HRESULT compile_retval_statement(compile_ctx_t *ctx, retval_statement_t * return S_OK; } +static HRESULT collect_const_decls(compile_ctx_t *ctx, statement_t *stat) +{ + HRESULT hres; + + while(stat) { + switch(stat->type) { + case STAT_CONST: { + const_statement_t *const_stat = (const_statement_t*)stat; + const_decl_t *decl; + + 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_args_name(ctx, decl->name) || lookup_dim_decls(ctx, decl->name)) { + FIXME("%s redefined\n", debugstr_w(decl->name)); + return E_FAIL; + } + + new_decl = compiler_alloc(ctx->code, sizeof(*new_decl)); + if(!new_decl) + return E_OUTOFMEMORY; + new_decl->name = decl->name; + new_decl->value_expr = decl->value_expr; + new_decl->next = ctx->const_decls; + ctx->const_decls = new_decl; + } + break; + } + case STAT_IF: { + if_statement_t *if_stat = (if_statement_t*)stat; + elseif_decl_t *elseif; + + hres = collect_const_decls(ctx, if_stat->if_stat); + if(FAILED(hres)) + return hres; + for(elseif = if_stat->elseifs; elseif; elseif = elseif->next) { + hres = collect_const_decls(ctx, elseif->stat); + if(FAILED(hres)) + return hres; + } + hres = collect_const_decls(ctx, if_stat->else_stat); + if(FAILED(hres)) + return hres; + break; + } + case STAT_WHILE: + case STAT_WHILELOOP: + case STAT_DOWHILE: + case STAT_DOUNTIL: + case STAT_UNTIL: { + while_statement_t *while_stat = (while_statement_t*)stat; + hres = collect_const_decls(ctx, while_stat->body); + if(FAILED(hres)) + return hres; + break; + } + case STAT_FORTO: { + forto_statement_t *forto_stat = (forto_statement_t*)stat; + hres = collect_const_decls(ctx, forto_stat->body); + if(FAILED(hres)) + return hres; + break; + } + case STAT_FOREACH: { + foreach_statement_t *foreach_stat = (foreach_statement_t*)stat; + hres = collect_const_decls(ctx, foreach_stat->body); + if(FAILED(hres)) + return hres; + break; + } + case STAT_SELECT: { + select_statement_t *select_stat = (select_statement_t*)stat; + case_clausule_t *clause; + for(clause = select_stat->case_clausules; clause; clause = clause->next) { + hres = collect_const_decls(ctx, clause->stat); + if(FAILED(hres)) + return hres; + } + break; + } + case STAT_WITH: { + with_statement_t *with_stat = (with_statement_t*)stat; + hres = collect_const_decls(ctx, with_stat->body); + if(FAILED(hres)) + return hres; + break; + } + case STAT_FUNC: + /* Don't recurse into sub/function bodies; they are compiled separately */ + break; + default: + break; + } + stat = stat->next; + } + return S_OK; +} + static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx, statement_t *stat) { HRESULT hres; @@ -1529,6 +1633,11 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f ctx->func = func; ctx->dim_decls = ctx->dim_decls_tail = NULL; ctx->const_decls = NULL; + + hres = collect_const_decls(ctx, stat); + if(FAILED(hres)) + return hres; + hres = compile_statement(ctx, NULL, stat); ctx->func = NULL; if(FAILED(hres)) diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 4374d7b1f25..49889609aa9 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -1502,6 +1502,13 @@ End Sub Call ConstTestSub Dim funcconst +if forward_const = 99 then + Call ok(true, "forward_const = 99") +else + Call ok(false, "forward_const <> 99") +end if +Const forward_const = 99 + ' Property may be used as an identifier (although it's a keyword) Sub TestProperty Dim Property diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 4b69bc18ffa..c8fbdf5b329 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -3489,6 +3489,21 @@ static void run_tests(void) CHECK_CALLED(global_success_d); CHECK_CALLED(global_success_i); + SET_EXPECT(OnScriptError); + hres = parse_script_wr(L"Const x = 1\nConst x = 2"); + ok(FAILED(hres), "duplicated const didn't fail\n"); + CHECK_CALLED(OnScriptError); + + SET_EXPECT(OnScriptError); + hres = parse_script_wr(L"Const x = 1\nDim x"); + ok(FAILED(hres), "const+dim didn't fail\n"); + CHECK_CALLED(OnScriptError); + + SET_EXPECT(OnScriptError); + hres = parse_script_wr(L"Dim x\nConst x = 1"); + ok(FAILED(hres), "dim+const didn't fail\n"); + CHECK_CALLED(OnScriptError); + run_from_res("lang.vbs"); run_from_res("api.vbs"); run_from_res("regexp.vbs"); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10302
This merge request was approved by Jacek Caban. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10302
participants (3)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb) -
Jacek Caban (@jacek)