[PATCH v2 1/4] vbscript: Add support for the SCRIPTTEXT_ISEXPRESSION flag in ParseScriptText.

Gabriel Ivăncescu gabrielopcode at gmail.com
Tue Sep 17 07:54:31 CDT 2019


To simplify the amount of special cases both in ParseScriptText and
ParseProcedureText, add a new pseudo statement and opcode 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 at gmail.com>
---
 dlls/vbscript/compile.c  | 22 ++++++++++++++++++++--
 dlls/vbscript/interp.c   | 26 ++++++++++++++++++++++++--
 dlls/vbscript/lex.c      |  6 ++++++
 dlls/vbscript/parse.h    | 10 ++++++++--
 dlls/vbscript/parser.y   | 31 ++++++++++++++++++++++++++++---
 dlls/vbscript/vbscript.c | 14 +++++++-------
 dlls/vbscript/vbscript.h |  3 ++-
 7 files changed, 95 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..6b9fd60 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -1258,6 +1258,30 @@ 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) {
+        VariantClear(&ctx->ret_val);
+        ctx->ret_val = *val.v;
+    }
+    else {
+        hres = VariantCopy(&ctx->ret_val, val.v);
+        if(FAILED(hres))
+            return hres;
+    }
+
+    return S_OK;
+}
+
 static HRESULT interp_stop(exec_ctx_t *ctx)
 {
     WARN("\n");
@@ -2179,8 +2203,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..510ac09 100644
--- a/dlls/vbscript/lex.c
+++ b/dlls/vbscript/lex.c
@@ -493,6 +493,12 @@ int parser_lex(void *lval, parser_ctx_t *ctx)
 {
     int ret;
 
+    if (ctx->last_token == tEXPRESSION)
+    {
+        ctx->last_token = tNL;
+        return tEXPRESSION;
+    }
+
     while(1) {
         ret = parse_next_token(lval, ctx);
         if(ret == '_') {
diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index 867d45f..659fefa 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;
@@ -268,7 +274,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..8ecdf47 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*);
@@ -102,7 +103,7 @@ static statement_t *link_statements(statement_t*,statement_t*);
     double dbl;
 }
 
-%token tEOF tNL tEMPTYBRACKETS
+%token tEXPRESSION tEOF tNL tEMPTYBRACKETS
 %token tLTEQ tGTEQ tNEQ
 %token tSTOP tME tREM
 %token <string> tTRUE tFALSE
@@ -123,7 +124,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
@@ -145,6 +146,7 @@ static statement_t *link_statements(statement_t*,statement_t*);
 
 Program
     : OptionExplicit_opt SourceElements tEOF    { parse_complete(ctx, $1); }
+    | tEXPRESSION ExpressionNl_opt tEOF         { handle_isexpression_script(ctx, $2); }
 
 OptionExplicit_opt
     : /* empty */                { $$ = FALSE; }
@@ -155,6 +157,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 +559,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 +1055,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};
 
@@ -1052,6 +1074,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->last_token = tEXPRESSION;
+
     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;
-- 
2.21.0




More information about the wine-devel mailing list