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

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Sep 16 08:05:05 CDT 2019


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 at 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;
-- 
2.21.0




More information about the wine-devel mailing list