To simplify the amount of special cases both in ParseScriptText and ParseProcedureText, a new pseudo statement and opcode have been added to return the expression and value at the top of the stack, respectively. Script texts that have this flag will be parsed specially as a single expression with such a statement at the end.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/compile.c | 22 ++++++++++++++++++++-- dlls/vbscript/interp.c | 29 +++++++++++++++++++++++++++-- dlls/vbscript/lex.c | 7 +++++++ dlls/vbscript/parse.h | 11 +++++++++-- dlls/vbscript/parser.y | 37 ++++++++++++++++++++++++++++++++++--- dlls/vbscript/vbscript.c | 14 +++++++------- dlls/vbscript/vbscript.h | 3 ++- 7 files changed, 106 insertions(+), 17 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 1f4a7d3..0527297 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1196,6 +1196,21 @@ static HRESULT compile_onerror_statement(compile_ctx_t *ctx, onerror_statement_t return push_instr_int(ctx, OP_errmode, stat->resume_next); }
+static HRESULT compile_retval_statement(compile_ctx_t *ctx, retval_statement_t *stat) +{ + HRESULT hres; + + hres = compile_expression(ctx, stat->expr); + if(FAILED(hres)) + return hres; + + hres = push_instr(ctx, OP_retval); + if(FAILED(hres)) + return hres; + + return S_OK; +} + static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx, statement_t *stat) { HRESULT hres; @@ -1267,6 +1282,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx, case STAT_WHILELOOP: hres = compile_while_statement(ctx, (while_statement_t*)stat); break; + case STAT_RETVAL: + hres = compile_retval_statement(ctx, (retval_statement_t*)stat); + break; default: FIXME("Unimplemented statement type %d\n", stat->type); hres = E_NOTIMPL; @@ -1795,7 +1813,7 @@ static void release_compiler(compile_ctx_t *ctx) release_vbscode(ctx->code); }
-HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *delimiter, vbscode_t **ret) +HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *delimiter, DWORD flags, vbscode_t **ret) { function_t *new_func; function_decl_t *func_decl; @@ -1804,7 +1822,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli vbscode_t *code; HRESULT hres;
- hres = parse_script(&ctx.parser, src, delimiter); + hres = parse_script(&ctx.parser, src, delimiter, flags); if(FAILED(hres)) return hres;
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 629e833..26aeab3 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1258,6 +1258,33 @@ static HRESULT interp_ret(exec_ctx_t *ctx) return S_OK; }
+static HRESULT interp_retval(exec_ctx_t *ctx) +{ + variant_val_t val; + HRESULT hres; + + TRACE("\n"); + + hres = stack_pop_val(ctx, &val); + if(FAILED(hres)) + return hres; + + if(val.owned) + ctx->ret_val = *val.v; + else { + VARIANT v; + + V_VT(&v) = VT_EMPTY; + hres = VariantCopy(&v, val.v); + if(FAILED(hres)) + return hres; + + ctx->ret_val = v; + } + + return S_OK; +} + static HRESULT interp_stop(exec_ctx_t *ctx) { WARN("\n"); @@ -2179,8 +2206,6 @@ HRESULT exec_script(script_ctx_t *ctx, function_t *func, vbdisp_t *vbthis, DISPP }
assert(!exec.top); - if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET) - assert(V_VT(&exec.ret_val) == VT_EMPTY);
if(SUCCEEDED(hres) && res) { *res = exec.ret_val; diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 4bcf810..d527c35 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -493,6 +493,13 @@ int parser_lex(void *lval, parser_ctx_t *ctx) { int ret;
+ if (ctx->start_token) + { + int tmp = ctx->start_token; + ctx->start_token = 0; + return tmp; + } + while(1) { ret = parse_next_token(lval, ctx); if(ret == '_') { diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h index 867d45f..174ec91 100644 --- a/dlls/vbscript/parse.h +++ b/dlls/vbscript/parse.h @@ -118,7 +118,8 @@ typedef enum { STAT_STOP, STAT_UNTIL, STAT_WHILE, - STAT_WHILELOOP + STAT_WHILELOOP, + STAT_RETVAL } statement_type_t;
typedef struct _statement_t { @@ -248,6 +249,11 @@ typedef struct { case_clausule_t *case_clausules; } select_statement_t;
+typedef struct { + statement_t stat; + expression_t *expr; +} retval_statement_t; + typedef struct { const WCHAR *code; const WCHAR *ptr; @@ -258,6 +264,7 @@ typedef struct { BOOL is_html; HRESULT hres;
+ int start_token; int last_token; unsigned last_nl;
@@ -268,7 +275,7 @@ typedef struct { heap_pool_t heap; } parser_ctx_t;
-HRESULT parse_script(parser_ctx_t*,const WCHAR*,const WCHAR*) DECLSPEC_HIDDEN; +HRESULT parse_script(parser_ctx_t*,const WCHAR*,const WCHAR*,DWORD) DECLSPEC_HIDDEN; void parser_release(parser_ctx_t*) DECLSPEC_HIDDEN; int parser_lex(void*,parser_ctx_t*) DECLSPEC_HIDDEN; void *parser_alloc(parser_ctx_t*,size_t) DECLSPEC_HIDDEN; diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index d4f5eb3..91ac0ed 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -28,6 +28,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript); static int parser_error(parser_ctx_t *,const char*);
static void parse_complete(parser_ctx_t*,BOOL); +static void handle_isexpression_script(parser_ctx_t *ctx, expression_t *expr);
static void source_add_statement(parser_ctx_t*,statement_t*); static void source_add_class(parser_ctx_t*,class_decl_t*); @@ -81,7 +82,9 @@ static statement_t *link_statements(statement_t*,statement_t*); %lex-param { parser_ctx_t *ctx } %parse-param { parser_ctx_t *ctx } %pure-parser -%start Program +%start Start +%token START_PROGRAM +%token START_EXPRESSION
%union { const WCHAR *string; @@ -123,7 +126,7 @@ static statement_t *link_statements(statement_t*,statement_t*); %token <dbl> tDouble
%type <statement> Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt BodyStatements IfStatement Else_opt -%type <expression> Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression +%type <expression> Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression ExpressionNl_opt %type <expression> ConcatExpression AdditiveExpression ModExpression IntdivExpression MultiplicativeExpression ExpExpression %type <expression> NotExpression UnaryExpression AndExpression OrExpression XorExpression EqvExpression %type <expression> ConstExpression NumericLiteralExpression @@ -143,6 +146,10 @@ static statement_t *link_statements(statement_t*,statement_t*);
%%
+Start + : START_PROGRAM Program + | START_EXPRESSION ExpressionNl_opt tEOF { handle_isexpression_script(ctx, $2); } + Program : OptionExplicit_opt SourceElements tEOF { parse_complete(ctx, $1); }
@@ -155,6 +162,10 @@ SourceElements | SourceElements StatementNl { source_add_statement(ctx, $2); } | SourceElements ClassDeclaration { source_add_class(ctx, $2); }
+ExpressionNl_opt + : /* empty */ { $$ = NULL; } + | Expression tNL { $$ = $1; } + BodyStatements : /* empty */ { $$ = NULL; } | Statement { $$ = $1; } @@ -553,6 +564,22 @@ static void parse_complete(parser_ctx_t *ctx, BOOL option_explicit) ctx->option_explicit = option_explicit; }
+static void handle_isexpression_script(parser_ctx_t *ctx, expression_t *expr) +{ + retval_statement_t *stat; + + ctx->parse_complete = TRUE; + if(!expr) + return; + + stat = new_statement(ctx, STAT_RETVAL, sizeof(*stat)); + if(!stat) + return; + + stat->expr = expr; + ctx->stats = &stat->stat; +} + static void *new_expression(parser_ctx_t *ctx, expression_type_t type, size_t size) { expression_t *expr; @@ -1033,7 +1060,7 @@ void *parser_alloc(parser_ctx_t *ctx, size_t size) return ret; }
-HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter) +HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter, DWORD flags) { static const WCHAR html_delimiterW[] = {'<','/','s','c','r','i','p','t','>',0};
@@ -1045,6 +1072,7 @@ HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimite ctx->parse_complete = FALSE; ctx->hres = S_OK;
+ ctx->start_token = START_PROGRAM; ctx->last_token = tNL; ctx->last_nl = 0; ctx->stats = ctx->stats_tail = NULL; @@ -1052,6 +1080,9 @@ HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimite ctx->option_explicit = FALSE; ctx->is_html = delimiter && !wcsicmp(delimiter, html_delimiterW);
+ if(flags & SCRIPTTEXT_ISEXPRESSION) + ctx->start_token = START_EXPRESSION; + parser_parse(ctx);
if(FAILED(ctx->hres)) diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index aa90b94..aa768a5 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -76,14 +76,14 @@ static inline BOOL is_started(VBScript *This) || This->state == SCRIPTSTATE_DISCONNECTED; }
-static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code) +static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res) { HRESULT hres;
code->pending_exec = FALSE;
IActiveScriptSite_OnEnterScript(ctx->site); - hres = exec_script(ctx, &code->main_code, NULL, NULL, NULL); + hres = exec_script(ctx, &code->main_code, NULL, NULL, res); IActiveScriptSite_OnLeaveScript(ctx->site);
return hres; @@ -95,7 +95,7 @@ static void exec_queued_code(script_ctx_t *ctx)
LIST_FOR_EACH_ENTRY(iter, &ctx->code_list, vbscode_t, entry) { if(iter->pending_exec) - exec_global_code(ctx, iter); + exec_global_code(ctx, iter, NULL); } }
@@ -719,19 +719,19 @@ static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface, } }
- hres = compile_script(This->ctx, pstrCode, pstrDelimiter, &code); + hres = compile_script(This->ctx, pstrCode, pstrDelimiter, dwFlags, &code); if(FAILED(hres)) return hres;
if(context) IDispatch_AddRef(code->context = context);
- if(!is_started(This)) { + if(!(dwFlags & SCRIPTTEXT_ISEXPRESSION) && !is_started(This)) { code->pending_exec = TRUE; return S_OK; }
- return exec_global_code(This->ctx, code); + return exec_global_code(This->ctx, code, pvarResult); }
static const IActiveScriptParseVtbl VBScriptParseVtbl = { @@ -782,7 +782,7 @@ static HRESULT WINAPI VBScriptParseProcedure_ParseProcedureText(IActiveScriptPar if(This->thread_id != GetCurrentThreadId() || This->state == SCRIPTSTATE_CLOSED) return E_UNEXPECTED;
- hres = compile_script(This->ctx, pstrCode, pstrDelimiter, &code); + hres = compile_script(This->ctx, pstrCode, pstrDelimiter, dwFlags, &code); if(FAILED(hres)) return hres;
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 2d78d5a..c9018c4 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -270,6 +270,7 @@ typedef enum { X(or, 1, 0, 0) \ X(pop, 1, ARG_UINT, 0) \ X(ret, 0, 0, 0) \ + X(retval, 1, 0, 0) \ X(set_ident, 1, ARG_BSTR, ARG_UINT) \ X(set_member, 1, ARG_BSTR, ARG_UINT) \ X(step, 0, ARG_ADDR, ARG_BSTR) \ @@ -353,7 +354,7 @@ struct _vbscode_t { };
void release_vbscode(vbscode_t*) DECLSPEC_HIDDEN; -HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,vbscode_t**) DECLSPEC_HIDDEN; +HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,DWORD,vbscode_t**) DECLSPEC_HIDDEN; HRESULT exec_script(script_ctx_t*,function_t*,vbdisp_t*,DISPPARAMS*,VARIANT*) DECLSPEC_HIDDEN; void release_dynamic_vars(dynamic_var_t*) DECLSPEC_HIDDEN; IDispatch *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned) DECLSPEC_HIDDEN;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/tests/run.c | 151 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 6 deletions(-)
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index f10a42b..1159daa 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -1792,7 +1792,7 @@ static IActiveScript *create_script(void) return script; }
-static IActiveScript *create_and_init_script(DWORD flags) +static IActiveScript *create_and_init_script(DWORD flags, BOOL start) { IActiveScriptParse *parser; IActiveScript *engine; @@ -1817,8 +1817,11 @@ static IActiveScript *create_and_init_script(DWORD flags) SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|flags); ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
- hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED); - ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres); + if (start) + { + hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres); + }
return engine; } @@ -1843,7 +1846,7 @@ static HRESULT parse_script(DWORD flags, BSTR script_str, const WCHAR *delim) LONG ref; HRESULT hres;
- engine = create_and_init_script(flags); + engine = create_and_init_script(flags, TRUE); if(!engine) return S_OK;
@@ -1907,7 +1910,7 @@ static void test_parse_context(void) static const WCHAR yW[] = {'y',0};
global_ref = 1; - engine = create_and_init_script(0); + engine = create_and_init_script(0, TRUE); if(!engine) return;
@@ -2004,7 +2007,7 @@ static void test_procedures(void) VARIANT v; HRESULT hres;
- script = create_and_init_script(0); + script = create_and_init_script(0, TRUE);
hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParseProcedure2, (void**)&parse_proc); ok(hres == S_OK, "Could not get IActiveScriptParseProcedure2 iface: %08x\n", hres); @@ -2239,6 +2242,141 @@ static HRESULT test_global_vars_ref(BOOL use_close) return hres; }
+static void test_isexpression(void) +{ + IActiveScriptParse *parser; + IActiveScript *engine; + SCRIPTSTATE ss; + HRESULT hres; + VARIANT var; + BSTR str; + + if (!(engine = create_and_init_script(0, FALSE))) + return; + + hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser); + ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres); + if (FAILED(hres)) + { + close_script(engine); + return; + } + + /* Expression when script is not started is still executed */ + hres = IActiveScript_GetScriptState(engine, &ss); + ok(hres == S_OK, "GetScriptState failed: %08x\n", hres); + ok(ss == SCRIPTSTATE_INITIALIZED, "Wrong script state %u\n", ss); + + str = a2bstr("13"); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_I2, "Expected VT_I2, got %s\n", vt2a(&var)); + ok(V_I2(&var) == 13, "Expected 13, got %d\n", V_I2(&var)); + VariantClear(&var); + SysFreeString(str); + + hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres); + + /* Empty expressions */ + V_VT(&var) = VT_I2; + str = a2bstr(""); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_EMPTY, "Expected VT_EMPTY, got %s\n", vt2a(&var)); + VariantClear(&var); + SysFreeString(str); + + /* Two expressions fail */ + str = a2bstr("1\n3"); + SET_EXPECT(OnScriptError); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(FAILED(hres), "ParseScriptText did not fail: %08x\n", hres); + todo_wine CHECK_CALLED(OnScriptError); + VariantClear(&var); + SysFreeString(str); + + /* Simple numerical expression */ + str = a2bstr("(1 + 7) * 2 - 3"); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_I2, "Expected VT_I2, got %s\n", vt2a(&var)); + ok(V_I2(&var) == 13, "Expected 13, got %d\n", V_I2(&var)); + VariantClear(&var); + SysFreeString(str); + + /* An expression can also refer to a variable, function, class, etc previously set */ + V_VT(&var) = VT_I2; + str = a2bstr("If True Then foo = 42 Else foo = 0\n"); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_EMPTY, "Expected VT_EMPTY, got %s\n", vt2a(&var)); + VariantClear(&var); + SysFreeString(str); + + str = a2bstr("foo\n\n"); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_I2, "Expected VT_I2, got %s\n", vt2a(&var)); + ok(V_I2(&var) == 42, "Expected 42, got %d\n", V_I2(&var)); + VariantClear(&var); + SysFreeString(str); + + str = a2bstr("foo : "); + SET_EXPECT(OnScriptError); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(FAILED(hres), "ParseScriptText did not fail: %08x\n", hres); + todo_wine CHECK_CALLED(OnScriptError); + VariantClear(&var); + SysFreeString(str); + + str = a2bstr(""foo is " & CStr(foo) \n \n\n "); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_BSTR, "Expected VT_BSTR, got %s\n", vt2a(&var)); + ok(!strcmp_wa(V_BSTR(&var), "foo is 42"), "Wrong string, got %s\n", wine_dbgstr_w(V_BSTR(&var))); + VariantClear(&var); + SysFreeString(str); + + str = a2bstr("Function test(x)\n" + " test = x + 0.5\n" + "End Function\n"); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + SysFreeString(str); + + str = a2bstr("test(4) * 3\n"); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_R8, "Expected VT_R8, got %s\n", vt2a(&var)); + ok(V_R8(&var) == 13.5, "Expected %lf, got %lf\n", 13.5, V_R8(&var)); + VariantClear(&var); + SysFreeString(str); + + str = a2bstr("Class C\n" + " Public x\n" + "End Class\n" + "Set obj = New C\n" + "obj.x = True\n"); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + SysFreeString(str); + + str = a2bstr("obj.x"); + hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + ok(V_VT(&var) == VT_BOOL, "Expected VT_BOOL, got %s\n", vt2a(&var)); + ok(V_BOOL(&var) == VARIANT_TRUE, "Expected %x, got %x\n", VARIANT_TRUE, V_BOOL(&var)); + VariantClear(&var); + SysFreeString(str); + + IActiveScriptParse_Release(parser); + close_script(engine); +} + static BSTR get_script_from_file(const char *filename) { DWORD size, len; @@ -2556,6 +2694,7 @@ static void run_tests(void) test_procedures(); test_gc(); test_msgbox(); + test_isexpression(); test_parse_errors(); test_parse_context(); }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Most of it works already due to implementing it in the compiler itself as an opcode. The only thing that's missing is to actually return the result.
dlls/vbscript/vbdisp.c | 2 +- include/activscp.idl | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index a907f40..0f6209f 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -626,7 +626,7 @@ static HRESULT Procedure_invoke(vbdisp_t *This, VARIANT *args, unsigned args_cnt TRACE("\n");
IActiveScriptSite_OnEnterScript(ctx->site); - hres = exec_script(ctx, This->desc->value_func, NULL, NULL, NULL); + hres = exec_script(ctx, This->desc->value_func, NULL, NULL, res); IActiveScriptSite_OnLeaveScript(ctx->site);
return hres; diff --git a/include/activscp.idl b/include/activscp.idl index 57179cf..97e7f5b 100644 --- a/include/activscp.idl +++ b/include/activscp.idl @@ -113,10 +113,12 @@ cpp_quote(" SCRIPTTEXT_ISVISIBLE | \") cpp_quote(" SCRIPTTEXT_ISEXPRESSION | \") cpp_quote(" SCRIPTTEXT_ISPERSISTENT | \") cpp_quote(" SCRIPTTEXT_HOSTMANAGESSOURCE)") +cpp_quote("#define SCRIPTPROC_ISEXPRESSION 0x00000020") cpp_quote("#define SCRIPTPROC_HOSTMANAGESSOURCE 0x00000080") cpp_quote("#define SCRIPTPROC_IMPLICIT_THIS 0x00000100") cpp_quote("#define SCRIPTPROC_IMPLICIT_PARENTS 0x00000200") -cpp_quote("#define SCRIPTPROC_ALL_FLAGS (SCRIPTPROC_HOSTMANAGESSOURCE | \") +cpp_quote("#define SCRIPTPROC_ALL_FLAGS (SCRIPTPROC_ISEXPRESSION | \") +cpp_quote(" SCRIPTPROC_HOSTMANAGESSOURCE | \") cpp_quote(" SCRIPTPROC_IMPLICIT_THIS | \") cpp_quote(" SCRIPTPROC_IMPLICIT_PARENTS)") cpp_quote("#define SCRIPTINFO_IUNKNOWN 0x00000001")
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/tests/run.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 1159daa..8e51e3c 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -1973,7 +1973,7 @@ static void _parse_htmlscript_a(unsigned line, const char *src) ok_(__FILE__,line)(hres == S_OK, "parse_script failed: %08x\n", hres); }
-static IDispatchEx *parse_procedure(IActiveScriptParseProcedure2 *parse_proc, const char *src) +static IDispatchEx *parse_procedure(IActiveScriptParseProcedure2 *parse_proc, const char *src, DWORD flags) { IDispatchEx *dispex; IDispatch *disp; @@ -1984,7 +1984,7 @@ static IDispatchEx *parse_procedure(IActiveScriptParseProcedure2 *parse_proc, co
str = a2bstr(src); hres = IActiveScriptParseProcedure2_ParseProcedureText(parse_proc, str, NULL, emptyW, NULL, NULL, delimiterW, 0, 0, - SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp); + SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS|flags, &disp); SysFreeString(str); ok(hres == S_OK, "ParseProcedureText failed: %08x\n", hres); ok(disp != NULL, "disp = NULL\n"); @@ -2012,12 +2012,20 @@ static void test_procedures(void) hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParseProcedure2, (void**)&parse_proc); ok(hres == S_OK, "Could not get IActiveScriptParseProcedure2 iface: %08x\n", hres);
- proc = parse_procedure(parse_proc, "dim x\nif true then x=false"); + proc = parse_procedure(parse_proc, "dim x\nif true then x=false", 0);
V_VT(&v) = VT_EMPTY; hres = IDispatchEx_InvokeEx(proc, DISPID_VALUE, 0, DISPATCH_METHOD, &dp, &v, &ei, &caller_sp); ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + VariantClear(&v); + IDispatchEx_Release(proc);
+ proc = parse_procedure(parse_proc, ""foobar"", SCRIPTPROC_ISEXPRESSION); + hres = IDispatchEx_InvokeEx(proc, DISPID_VALUE, 0, DISPATCH_METHOD, &dp, &v, &ei, &caller_sp); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + ok(V_VT(&v) == VT_BSTR, "Expected VT_BSTR, got %s\n", vt2a(&v)); + ok(!strcmp_wa(V_BSTR(&v), "foobar"), "Wrong string, got %s\n", wine_dbgstr_w(V_BSTR(&v))); + VariantClear(&v); IDispatchEx_Release(proc);
IActiveScriptParseProcedure2_Release(parse_proc);
Hi Gabriel,
The patch looks mostly good, a few comments below.
On 9/16/19 3:05 PM, Gabriel Ivăncescu wrote:
To simplify the amount of special cases both in ParseScriptText and ParseProcedureText, a new pseudo statement and opcode have been added to return the expression and value at the top of the stack, respectively. Script texts that have this flag will be parsed specially as a single expression with such a statement at the end.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
dlls/vbscript/compile.c | 22 ++++++++++++++++++++-- dlls/vbscript/interp.c | 29 +++++++++++++++++++++++++++-- dlls/vbscript/lex.c | 7 +++++++ dlls/vbscript/parse.h | 11 +++++++++-- dlls/vbscript/parser.y | 37 ++++++++++++++++++++++++++++++++++--- dlls/vbscript/vbscript.c | 14 +++++++------- dlls/vbscript/vbscript.h | 3 ++- 7 files changed, 106 insertions(+), 17 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 1f4a7d3..0527297 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -1196,6 +1196,21 @@ static HRESULT compile_onerror_statement(compile_ctx_t *ctx, onerror_statement_t return push_instr_int(ctx, OP_errmode, stat->resume_next); }
+static HRESULT compile_retval_statement(compile_ctx_t *ctx, retval_statement_t *stat) +{
- HRESULT hres;
- hres = compile_expression(ctx, stat->expr);
- if(FAILED(hres))
return hres;
- hres = push_instr(ctx, OP_retval);
- if(FAILED(hres))
return hres;
- return S_OK;
+}
- static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx, statement_t *stat) { HRESULT hres;
@@ -1267,6 +1282,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx, case STAT_WHILELOOP: hres = compile_while_statement(ctx, (while_statement_t*)stat); break;
case STAT_RETVAL:
hres = compile_retval_statement(ctx, (retval_statement_t*)stat);
break;
As a side note, for a possible future optimization, we could also try to statically catch assignments to retval and emit OP_retval for them as well.
+static HRESULT interp_retval(exec_ctx_t *ctx) +{
- variant_val_t val;
- HRESULT hres;
- TRACE("\n");
- hres = stack_pop_val(ctx, &val);
- if(FAILED(hres))
return hres;
- if(val.owned)
ctx->ret_val = *val.v;
- else {
VARIANT v;
V_VT(&v) = VT_EMPTY;
hres = VariantCopy(&v, val.v);
if(FAILED(hres))
return hres;
ctx->ret_val = v;
Technically you're leaking previous ret_val value (although current compiler would never emit leaking code). You could just pass ret_val as VariantCopy destination.
diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 4bcf810..d527c35 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -493,6 +493,13 @@ int parser_lex(void *lval, parser_ctx_t *ctx) { int ret;
- if (ctx->start_token)
- {
int tmp = ctx->start_token;
ctx->start_token = 0;
return tmp;
- }
Could we use already existing last_token here?
if(ctx->last_token == tEXPRESSION) {
ctx->last_token = tNL;
return tEXPRESSION;
}
@@ -81,7 +82,9 @@ static statement_t *link_statements(statement_t*,statement_t*); %lex-param { parser_ctx_t *ctx } %parse-param { parser_ctx_t *ctx } %pure-parser -%start Program +%start Start +%token START_PROGRAM
Do you really need both START_PROGRAM and START_EXPRESSION? It seems to me that having just one of them should be enough.
+%token START_EXPRESSION
tEXPRESSION or tSTART_EXPRESSION would be more consistent with other tokens.
Thanks,
Jacek
Hi Jacek,
Right. Thanks for the review, I've sent an updated patch that should fix it.