78843: Subject: [PATCH 12/21] vbscript: Added Exit Function statement implementation

buildbot at kegel.com buildbot at kegel.com
Wed Sep 14 09:26:26 CDT 2011


This is an experimental automated build and test service.
Please feel free to ignore this email while we work the kinks out.

For more info about this message, see http://wiki.winehq.org/BuildBot

The Buildbot has detected a failed build on builder runtests-heaptest while building Wine.
Full details are available at: http://buildbot.kegel.com/builders/runtests-heaptest/builds/36 (though maybe not for long, as I'm still reinstalling the buildbot periodically while experimenting)
BUILD FAILED: failed shell_3

Errors:
vbscript.c:443: Test failed: expected OnEnterScript
vbscript.c:444: Test failed: expected OnLeaveScript
make: *** [vbscript.ok] Error 2

-------------- next part --------------
From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 01/21] vbscript: Added sub statement parser implementation
Message-Id: <4E7087FA.4090207 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:54:50 +0200

---
  dlls/vbscript/parse.h    |   24 +++++++++++++-
  dlls/vbscript/parser.y   |   75 
++++++++++++++++++++++++++++++++++++++++++++-
  dlls/vbscript/vbscript.h |    5 +++
  3 files changed, 100 insertions(+), 4 deletions(-)

diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index cfeb8c0..9b837c2 100644
--- a/dlls/vbscript/parse.h
+++ b/dlls/vbscript/parse.h
@@ -85,8 +85,9 @@ typedef struct {
 typedef enum {
     STAT_ASSIGN,
     STAT_CALL,
-    STAT_IF,
-    STAT_DIM
+    STAT_DIM,
+    STAT_FUNC,
+    STAT_IF
 } statement_type_t;
 
 typedef struct _statement_t {
@@ -115,6 +116,25 @@ typedef struct _dim_statement_t {
     dim_decl_t *dim_decls;
 } dim_statement_t;
 
+typedef struct _arg_decl_t {
+    const WCHAR *name;
+    BOOL by_ref;
+    struct _arg_decl_t *next;
+} arg_decl_t;
+
+typedef struct _function_decl_t {
+    const WCHAR *name;
+    function_type_t type;
+    arg_decl_t *args;
+    statement_t *body;
+    struct _function_decl_t *next;
+} function_decl_t;
+
+typedef struct _function_statement_t {
+    statement_t stat;
+    function_decl_t *func_decl;
+} function_statement_t;
+
 typedef struct _elseif_decl_t {
     expression_t *expr;
     statement_t *stat;
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index c9f9c76..4964d71 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -48,10 +48,13 @@ static member_expression_t *new_member_expression(parser_ctx_t*,expression_t*,co
 static statement_t *new_call_statement(parser_ctx_t*,member_expression_t*);
 static statement_t *new_assign_statement(parser_ctx_t*,member_expression_t*,expression_t*);
 static statement_t *new_dim_statement(parser_ctx_t*,dim_decl_t*);
- static statement_t *new_if_statement(parser_ctx_t*,expression_t*,statement_t*,elseif_decl_t*,statement_t*);
+static statement_t *new_if_statement(parser_ctx_t*,expression_t*,statement_t*,elseif_decl_t*,statement_t*);
+static statement_t *new_function_statement(parser_ctx_t*,function_decl_t*);
 
 static dim_decl_t *new_dim_decl(parser_ctx_t*,const WCHAR*,dim_decl_t*);
 static elseif_decl_t *new_elseif_decl(parser_ctx_t*,expression_t*,statement_t*);
+static function_decl_t *new_function_decl(parser_ctx_t*,const WCHAR*,function_type_t,arg_decl_t*,statement_t*);
+static arg_decl_t *new_argument_decl(parser_ctx_t*,const WCHAR*,BOOL);
 
 #define CHECK_ERROR if(((parser_ctx_t*)ctx)->hres != S_OK) YYABORT
 
@@ -67,6 +70,8 @@ static elseif_decl_t *new_elseif_decl(parser_ctx_t*,expression_t*,statement_t*);
     member_expression_t *member;
     elseif_decl_t *elseif;
     dim_decl_t *dim_decl;
+    function_decl_t *func_decl;
+    arg_decl_t *arg_decl;
     LONG lng;
     BOOL bool;
     double dbl;
@@ -89,13 +94,15 @@ static elseif_decl_t *new_elseif_decl(parser_ctx_t*,expression_t*,statement_t*);
 %token <lng> tLong tShort
 %token <dbl> tDouble
 
-%type <statement> Statement StatementNl StatementsNl IfStatement Else_opt
+%type <statement> Statement StatementNl StatementsNl StatementsNl_opt IfStatement Else_opt
 %type <expression> Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression
 %type <expression> ConcatExpression AdditiveExpression ModExpression IntdivExpression MultiplicativeExpression ExpExpression
 %type <expression> NotExpression UnaryExpression
 %type <member> MemberExpression
 %type <expression> Arguments_opt ArgumentList_opt ArgumentList
 %type <bool> OptionExplicit_opt
+%type <arg_decl> ArgumentsDecl_opt ArgumentDeclList ArgumentDecl
+%type <func_decl> FunctionDecl
 %type <elseif> ElseIfs_opt ElseIfs ElseIf
 %type <dim_decl> DimDeclList
 
@@ -112,6 +119,10 @@ SourceElements
     : /* empty */
     | SourceElements StatementNl    { source_add_statement(ctx, $2); }
 
+StatementsNl_opt
+    : /* empty */                           { $$ = NULL; }
+    | StatementsNl                          { $$ = $1; }
+
 StatementsNl
     : StatementNl                           { $$ = $1; }
     | StatementNl StatementsNl              { $1->next = $2; $$ = $1; }
@@ -126,6 +137,7 @@ Statement
                                             { $1->args = $2; $$ = new_assign_statement(ctx, $1, $4); CHECK_ERROR; }
     | tDIM DimDeclList                      { $$ = new_dim_statement(ctx, $2); CHECK_ERROR; }
     | IfStatement                           { $$ = $1; }
+    | FunctionDecl                          { $$ = new_function_statement(ctx, $1); CHECK_ERROR; }
 
 MemberExpression
     : tIdentifier                           { $$ = new_member_expression(ctx, NULL, $1); CHECK_ERROR; }
@@ -236,6 +248,23 @@ LiteralExpression
 PrimaryExpression
     : '(' Expression ')'            { $$ = $2; }
 
+FunctionDecl
+    : /* Storage_opt */ tSUB tIdentifier ArgumentsDecl_opt tNL StatementsNl_opt tEND tSUB
+                                    { $$ = new_function_decl(ctx, $2, FUNC_SUB, $3, $5); CHECK_ERROR; }
+
+ArgumentsDecl_opt
+    : EmptyBrackets_opt                         { $$ = NULL; }
+    | '(' ArgumentDeclList ')'                  { $$ = $2; }
+
+ArgumentDeclList
+    : ArgumentDecl                              { $$ = $1; }
+    | ArgumentDecl ',' ArgumentDeclList         { $1->next = $3; $$ = $1; }
+
+ArgumentDecl
+    : tIdentifier                               { $$ = new_argument_decl(ctx, $1, TRUE); }
+    | tBYREF tIdentifier                        { $$ = new_argument_decl(ctx, $2, TRUE); }
+    | tBYVAL tIdentifier                        { $$ = new_argument_decl(ctx, $2, FALSE); }
+
 %%
 
 static int parser_error(const char *str)
@@ -452,6 +481,48 @@ static statement_t *new_if_statement(parser_ctx_t *ctx, expression_t *expr, stat
     return &stat->stat;
 }
 
+static arg_decl_t *new_argument_decl(parser_ctx_t *ctx, const WCHAR *name, BOOL by_ref)
+{
+    arg_decl_t *arg_decl;
+
+    arg_decl = parser_alloc(ctx, sizeof(*arg_decl));
+    if(!arg_decl)
+        return NULL;
+
+    arg_decl->name = name;
+    arg_decl->by_ref = by_ref;
+    arg_decl->next = NULL;
+    return arg_decl;
+}
+
+static function_decl_t *new_function_decl(parser_ctx_t *ctx, const WCHAR *name, function_type_t type,
+        arg_decl_t *arg_decl, statement_t *body)
+{
+    function_decl_t *decl;
+
+    decl = parser_alloc(ctx, sizeof(*decl));
+    if(!decl)
+        return NULL;
+
+    decl->name = name;
+    decl->type = type;
+    decl->args = arg_decl;
+    decl->body = body;
+    return decl;
+}
+
+static statement_t *new_function_statement(parser_ctx_t *ctx, function_decl_t *decl)
+{
+    function_statement_t *stat;
+
+    stat = new_statement(ctx, STAT_FUNC, sizeof(*stat));
+    if(!stat)
+        return NULL;
+
+    stat->func_decl = decl;
+    return &stat->stat;
+}
+
 void *parser_alloc(parser_ctx_t *ctx, size_t size)
 {
     void *ret;
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index afa9d83..b52aa09 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -146,6 +146,11 @@ typedef struct {
     instr_arg_t arg2;
 } instr_t;
 
+typedef enum {
+    FUNC_GLOBAL,
+    FUNC_SUB
+} function_type_t;
+
 struct _function_t {
     unsigned code_off;
     vbscode_t *code_ctx;

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 02/21] vbscript: Added function compiler implementation
Message-Id: <4E70880B.8010305 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:55:07 +0200

---
  dlls/vbscript/compile.c      |  142 
+++++++++++++++++++++++++++++++++++------
  dlls/vbscript/tests/lang.vbs |    6 ++
  dlls/vbscript/vbscript.h     |    3 +
  3 files changed, 130 insertions(+), 21 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index d39b94e..4e8cd06 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -40,6 +40,10 @@ typedef struct {
 
     dim_decl_t *dim_decls;
     dynamic_var_t *global_vars;
+
+    function_t *func;
+    function_t *funcs;
+    function_decl_t *func_decls;
 } compile_ctx_t;
 
 static HRESULT compile_expression(compile_ctx_t*,expression_t*);
@@ -514,6 +518,18 @@ static HRESULT compile_dim_statement(compile_ctx_t *ctx, dim_statement_t *stat)
     return S_OK;
 }
 
+static HRESULT compile_function_statement(compile_ctx_t *ctx, function_statement_t *stat)
+{
+    if(ctx->func != &ctx->code->global_code) {
+        FIXME("Function is not in the global code\n");
+        return E_FAIL;
+    }
+
+    stat->func_decl->next = ctx->func_decls;
+    ctx->func_decls = stat->func_decl;
+    return S_OK;
+}
+
 static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
 {
     HRESULT hres;
@@ -529,6 +545,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
         case STAT_DIM:
             hres = compile_dim_statement(ctx, (dim_statement_t*)stat);
             break;
+        case STAT_FUNC:
+            hres = compile_function_statement(ctx, (function_statement_t*)stat);
+            break;
         case STAT_IF:
             hres = compile_if_statement(ctx, (if_statement_t*)stat);
             break;
@@ -545,11 +564,11 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
     return S_OK;
 }
 
-static void resolve_labels(compile_ctx_t *ctx)
+static void resolve_labels(compile_ctx_t *ctx, unsigned off)
 {
     instr_t *instr;
 
-    for(instr = ctx->code->instrs; instr < ctx->code->instrs+ctx->instr_cnt; instr++) {
+    for(instr = ctx->code->instrs+off; instr < ctx->code->instrs+ctx->instr_cnt; instr++) {
         if(instr_info[instr->op].arg1_type == ARG_ADDR && (instr->arg1.uint & LABEL_FLAG)) {
             assert((instr->arg1.uint & ~LABEL_FLAG) < ctx->labels_cnt);
             instr->arg1.uint = ctx->labels[instr->arg1.uint & ~LABEL_FLAG];
@@ -566,38 +585,92 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f
 
     func->code_off = ctx->instr_cnt;
 
+    ctx->func = func;
+    ctx->dim_decls = NULL;
     hres = compile_statement(ctx, stat);
+    ctx->func = NULL;
     if(FAILED(hres))
         return hres;
 
     if(push_instr(ctx, OP_ret) == -1)
         return E_OUTOFMEMORY;
 
-    resolve_labels(ctx);
+    resolve_labels(ctx, func->code_off);
 
     if(ctx->dim_decls) {
         dim_decl_t *dim_decl;
-        dynamic_var_t *new_var;
 
-        for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) {
-            new_var = compiler_alloc(ctx->code, sizeof(*new_var));
-            if(!new_var)
-                return E_OUTOFMEMORY;
+        if(func->type == FUNC_GLOBAL) {
+            dynamic_var_t *new_var;
 
-            new_var->name = compiler_alloc_string(ctx->code, dim_decl->name);
-            if(!new_var->name)
-                return E_OUTOFMEMORY;
+            for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) {
+                new_var = compiler_alloc(ctx->code, sizeof(*new_var));
+                if(!new_var)
+                    return E_OUTOFMEMORY;
 
-            V_VT(&new_var->v) = VT_EMPTY;
+                new_var->name = compiler_alloc_string(ctx->code, dim_decl->name);
+                if(!new_var->name)
+                    return E_OUTOFMEMORY;
 
-            new_var->next = ctx->global_vars;
-            ctx->global_vars = new_var;
+                V_VT(&new_var->v) = VT_EMPTY;
+
+                new_var->next = ctx->global_vars;
+                ctx->global_vars = new_var;
+            }
+        }else {
+            FIXME("var not implemented for functions\n");
         }
     }
 
     return S_OK;
 }
 
+static BOOL lookup_funcs_name(compile_ctx_t *ctx, const WCHAR *name)
+{
+    function_t *iter;
+
+    for(iter = ctx->funcs; iter; iter = iter->next) {
+        if(!strcmpiW(iter->name, name))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, function_t **ret)
+{
+    function_t *func;
+    HRESULT hres;
+
+    if(lookup_dim_decls(ctx, decl->name) || lookup_funcs_name(ctx, decl->name)) {
+        FIXME("%s: redefinition\n", debugstr_w(decl->name));
+        return E_FAIL;
+    }
+
+    func = compiler_alloc(ctx->code, sizeof(*func));
+    if(!func)
+        return E_OUTOFMEMORY;
+
+    func->name = compiler_alloc_string(ctx->code, decl->name);
+    if(!func->name)
+        return E_OUTOFMEMORY;
+
+    func->code_ctx = ctx->code;
+    func->type = decl->type;
+
+    if(decl->args) {
+        FIXME("arguments not implemented\n");
+        return E_NOTIMPL;
+    }
+
+    hres = compile_func(ctx, decl->body, func);
+    if(FAILED(hres))
+        return hres;
+
+    *ret = func;
+    return S_OK;
+}
+
 static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifier)
 {
     dynamic_var_t *var;
@@ -671,25 +744,40 @@ static vbscode_t *alloc_vbscode(compile_ctx_t *ctx, const WCHAR *source)
     ret->bstr_pool_size = 0;
     ret->bstr_cnt = 0;
 
+    ret->global_code.type = FUNC_GLOBAL;
+    ret->global_code.name = NULL;
     ret->global_code.code_ctx = ret;
 
     list_init(&ret->entry);
     return ret;
 }
 
+static void release_compiler(compile_ctx_t *ctx)
+{
+    parser_release(&ctx->parser);
+    heap_free(ctx->labels);
+    if(ctx->code)
+        release_vbscode(ctx->code);
+}
+
 HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
 {
+    function_t *new_func;
+    function_decl_t *func_decl;
     compile_ctx_t ctx;
+    vbscode_t *code;
     HRESULT hres;
 
     hres = parse_script(&ctx.parser, src);
     if(FAILED(hres))
         return hres;
 
-    ctx.code = alloc_vbscode(&ctx, src);
+    code = ctx.code = alloc_vbscode(&ctx, src);
     if(!ctx.code)
         return E_OUTOFMEMORY;
 
+    ctx.funcs = NULL;
+    ctx.func_decls = NULL;
     ctx.global_vars = NULL;
     ctx.dim_decls = NULL;
     ctx.labels = NULL;
@@ -697,13 +785,24 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
 
     hres = compile_func(&ctx, ctx.parser.stats, &ctx.code->global_code);
     if(FAILED(hres)) {
-        release_vbscode(ctx.code);
+        release_compiler(&ctx);
         return hres;
     }
 
+    for(func_decl = ctx.func_decls; func_decl; func_decl = func_decl->next) {
+        hres = create_function(&ctx, func_decl, &new_func);
+        if(FAILED(hres)) {
+            release_compiler(&ctx);
+            return hres;
+        }
+
+        new_func->next = ctx.funcs;
+        ctx.funcs = new_func;
+    }
+
     hres = check_script_collisions(&ctx, script);
     if(FAILED(hres)) {
-        release_vbscode(ctx.code);
+        release_compiler(&ctx);
         return hres;
     }
 
@@ -716,12 +815,13 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
         script->global_vars = ctx.global_vars;
     }
 
-    parser_release(&ctx.parser);
-
     if(TRACE_ON(vbscript_disas))
         dump_code(&ctx);
 
-    list_add_tail(&script->code_list, &ctx.code->entry);
-    *ret = ctx.code;
+    ctx.code = NULL;
+    release_compiler(&ctx);
+
+    list_add_tail(&script->code_list, &code->entry);
+    *ret = code;
     return S_OK;
 }
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 12bdaf5..60ca988 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -169,4 +169,10 @@ ElseIf not False Then
 End If
 Call ok(x, "elseif not called?")
 
+if false then
+Sub testsub
+    x = true
+End Sub
+end if
+
 reportSuccess()
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index b52aa09..41dea38 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -152,8 +152,11 @@ typedef enum {
 } function_type_t;
 
 struct _function_t {
+    function_type_t type;
+    const WCHAR *name;
     unsigned code_off;
     vbscode_t *code_ctx;
+    function_t *next;
 };
 
 struct _vbscode_t {

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 03/21] vbscript: Store global functions in script_ctx_t
Message-Id: <4E708824.1060000 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:55:32 +0200

---
  dlls/vbscript/compile.c  |   21 +++++++++++++++++++++
  dlls/vbscript/vbscript.h |    1 +
  2 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index 4e8cd06..651bf7c 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -674,18 +674,25 @@ static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, functi
 static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifier)
 {
     dynamic_var_t *var;
+    function_t *func;
 
     for(var = script->global_vars; var; var = var->next) {
         if(!strcmpiW(var->name, identifier))
             return TRUE;
     }
 
+    for(func = script->global_funcs; func; func = func->next) {
+        if(!strcmpiW(func->name, identifier))
+            return TRUE;
+    }
+
     return FALSE;
 }
 
 static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script)
 {
     dynamic_var_t *var;
+    function_t *func;
 
     for(var = ctx->global_vars; var; var = var->next) {
         if(lookup_script_identifier(script, var->name)) {
@@ -694,6 +701,13 @@ static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script)
         }
     }
 
+    for(func = ctx->funcs; func; func = func->next) {
+        if(lookup_script_identifier(script, func->name)) {
+            FIXME("%s: redefined\n", debugstr_w(func->name));
+            return E_FAIL;
+        }
+    }
+
     return S_OK;
 }
 
@@ -815,6 +829,13 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
         script->global_vars = ctx.global_vars;
     }
 
+    if(ctx.funcs) {
+        for(new_func = ctx.funcs; new_func->next; new_func = new_func->next);
+
+        new_func->next = script->global_funcs;
+        script->global_funcs = ctx.funcs;
+    }
+
     if(TRACE_ON(vbscript_disas))
         dump_code(&ctx);
 
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 41dea38..32b19ab 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -80,6 +80,7 @@ struct _script_ctx_t {
     vbdisp_t *script_obj;
 
     dynamic_var_t *global_vars;
+    function_t *global_funcs;
 
     struct list code_list;
     struct list named_items;

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 04/21] vbscript: Added functions lookup implementation
Message-Id: <4E70882E.90803 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:55:42 +0200

---
  dlls/vbscript/interp.c |   19 ++++++++++++++++++-
  1 files changed, 18 insertions(+), 1 deletions(-)

diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index 593c83e..25fd6bb 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -41,7 +41,8 @@ typedef HRESULT (*instr_func_t)(exec_ctx_t*);
 typedef enum {
     REF_NONE,
     REF_DISP,
-    REF_VAR
+    REF_VAR,
+    REF_FUNC
 } ref_type_t;
 
 typedef struct {
@@ -52,6 +53,7 @@ typedef struct {
             DISPID id;
         } d;
         VARIANT *v;
+        function_t *f;
     } u;
 } ref_t;
 
@@ -79,12 +81,21 @@ static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *re
 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, ref_t *ref)
 {
     named_item_t *item;
+    function_t *func;
     DISPID id;
     HRESULT hres;
 
     if(lookup_dynamic_vars(ctx->script->global_vars, name, ref))
         return S_OK;
 
+    for(func = ctx->script->global_funcs; func; func = func->next) {
+        if(!strcmpiW(func->name, name)) {
+            ref->type = REF_FUNC;
+            ref->u.f = func;
+            return S_OK;
+        }
+    }
+
     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
         if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
             hres = disp_get_id(item->disp, name, &id);
@@ -254,6 +265,9 @@ static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
         if(FAILED(hres))
             return hres;
         break;
+    case REF_FUNC:
+        FIXME("functions not implemented\n");
+        return E_NOTIMPL;
     case REF_NONE:
         FIXME("%s not found\n", debugstr_w(identifier));
         return DISP_E_UNKNOWNNAME;
@@ -313,6 +327,9 @@ static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_v
         if(own_val)
             VariantClear(val);
         break;
+    case REF_FUNC:
+        FIXME("functions not implemented\n");
+        return E_NOTIMPL;
     case REF_NONE:
         FIXME("%s not found\n", debugstr_w(name));
         if(own_val)

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 05/21] vbscript: Added function invocation supprot to do_icall
Message-Id: <4E708841.7010503 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:56:01 +0200

---
  dlls/vbscript/interp.c       |   18 +++++++++++++++---
  dlls/vbscript/tests/lang.vbs |    4 ++++
  dlls/vbscript/vbscript.c     |    2 +-
  dlls/vbscript/vbscript.h     |    7 ++++++-
  4 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index 25fd6bb..34d0d2f 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -266,8 +266,10 @@ static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
             return hres;
         break;
     case REF_FUNC:
-        FIXME("functions not implemented\n");
-        return E_NOTIMPL;
+        hres = exec_script(ctx->script, ref.u.f, &dp, res);
+        if(FAILED(hres))
+            return hres;
+        break;
     case REF_NONE:
         FIXME("%s not found\n", debugstr_w(identifier));
         return DISP_E_UNKNOWNNAME;
@@ -809,12 +811,22 @@ OP_LIST
 #undef X
 };
 
-HRESULT exec_script(script_ctx_t *ctx, function_t *func)
+HRESULT exec_script(script_ctx_t *ctx, function_t *func, DISPPARAMS *dp, VARIANT *res)
 {
     exec_ctx_t exec;
     vbsop_t op;
     HRESULT hres = S_OK;
 
+    if(res) {
+        FIXME("returning value is not implemented\n");
+        return E_NOTIMPL;
+    }
+
+    if(dp && arg_cnt(dp)) {
+        FIXME("arguments not implemented\n");
+        return E_NOTIMPL;
+    }
+
     exec.stack_size = 16;
     exec.top = 0;
     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 60ca988..0c4c10f 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -175,4 +175,8 @@ Sub testsub
 End Sub
 end if
 
+x = false
+Call testsub
+Call ok(x, "x is false, testsub not called?")
+
 reportSuccess()
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c
index f6891c7..cb28a9a 100644
--- a/dlls/vbscript/vbscript.c
+++ b/dlls/vbscript/vbscript.c
@@ -77,7 +77,7 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code)
     code->global_executed = TRUE;
 
     IActiveScriptSite_OnEnterScript(ctx->site);
-    hres = exec_script(ctx, &code->global_code);
+    hres = exec_script(ctx, &code->global_code, NULL, NULL);
     IActiveScriptSite_OnLeaveScript(ctx->site);
 
     return hres;
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 32b19ab..d541e9d 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -65,6 +65,11 @@ HRESULT disp_get_id(IDispatch*,BSTR,DISPID*);
 HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,DISPPARAMS*,VARIANT*);
 HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,VARIANT*);
 
+static inline unsigned arg_cnt(const DISPPARAMS *dp)
+{
+    return dp->cArgs - dp->cNamedArgs;
+}
+
 typedef struct _dynamic_var_t {
     struct _dynamic_var_t *next;
     VARIANT v;
@@ -179,7 +184,7 @@ struct _vbscode_t {
 
 void release_vbscode(vbscode_t*) DECLSPEC_HIDDEN;
 HRESULT compile_script(script_ctx_t*,const WCHAR*,vbscode_t**) DECLSPEC_HIDDEN;
-HRESULT exec_script(script_ctx_t*,function_t*) DECLSPEC_HIDDEN;
+HRESULT exec_script(script_ctx_t*,function_t*,DISPPARAMS*,VARIANT*) DECLSPEC_HIDDEN;
 
 HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**);
 

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 06/21] vbscript: Added function arguments compiler implementation
Message-Id: <4E70885B.9010400 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:56:27 +0200

---
  dlls/vbscript/compile.c  |   23 +++++++++++++++++++++--
  dlls/vbscript/vbscript.h |    7 +++++++
  2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index 651bf7c..bdff74d 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -658,9 +658,26 @@ static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, functi
     func->code_ctx = ctx->code;
     func->type = decl->type;
 
+    func->arg_cnt = 0;
     if(decl->args) {
-        FIXME("arguments not implemented\n");
-        return E_NOTIMPL;
+        arg_decl_t *arg;
+        unsigned i;
+
+        for(arg = decl->args; arg; arg = arg->next)
+            func->arg_cnt++;
+
+        func->args = compiler_alloc(ctx->code, func->arg_cnt * sizeof(arg_desc_t));
+        if(!func->args)
+            return E_OUTOFMEMORY;
+
+        for(i = 0, arg = decl->args; arg; arg = arg->next, i++) {
+            func->args[i].name = compiler_alloc_string(ctx->code, arg->name);
+            if(!func->args[i].name)
+                return E_OUTOFMEMORY;
+            func->args[i].by_ref = arg->by_ref;
+        }
+    }else {
+        decl->args = NULL;
     }
 
     hres = compile_func(ctx, decl->body, func);
@@ -761,6 +778,8 @@ static vbscode_t *alloc_vbscode(compile_ctx_t *ctx, const WCHAR *source)
     ret->global_code.type = FUNC_GLOBAL;
     ret->global_code.name = NULL;
     ret->global_code.code_ctx = ret;
+    ret->global_code.arg_cnt = 0;
+    ret->global_code.args = NULL;
 
     list_init(&ret->entry);
     return ret;
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index d541e9d..0e6d57e 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -152,6 +152,11 @@ typedef struct {
     instr_arg_t arg2;
 } instr_t;
 
+typedef struct {
+    const WCHAR *name;
+    BOOL by_ref;
+} arg_desc_t;
+
 typedef enum {
     FUNC_GLOBAL,
     FUNC_SUB
@@ -160,6 +165,8 @@ typedef enum {
 struct _function_t {
     function_type_t type;
     const WCHAR *name;
+    arg_desc_t *args;
+    unsigned arg_cnt;
     unsigned code_off;
     vbscode_t *code_ctx;
     function_t *next;

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 07/21] vbscript: Added interpreter support for sub arguments
Message-Id: <4E70886D.1080303 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:56:45 +0200

---
  dlls/vbscript/interp.c   |   70 
+++++++++++++++++++++++++++++++++++++++++----
  dlls/vbscript/vbscript.h |    5 +++
  2 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index 34d0d2f..68fb4ed 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -31,6 +31,8 @@ typedef struct {
     script_ctx_t *script;
     function_t *func;
 
+    VARIANT *args;
+
     unsigned stack_size;
     unsigned top;
     VARIANT *stack;
@@ -82,9 +84,18 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, ref_t *ref)
 {
     named_item_t *item;
     function_t *func;
+    unsigned i;
     DISPID id;
     HRESULT hres;
 
+    for(i=0; i < ctx->func->arg_cnt; i++) {
+        if(!strcmpiW(ctx->func->args[i].name, name)) {
+            ref->type = REF_VAR;
+            ref->u.v = ctx->args+i;
+            return S_OK;
+        }
+    }
+
     if(lookup_dynamic_vars(ctx->script->global_vars, name, ref))
         return S_OK;
 
@@ -811,9 +822,22 @@ OP_LIST
 #undef X
 };
 
+static void release_exec(exec_ctx_t *ctx)
+{
+    if(ctx->args) {
+        unsigned i;
+
+        for(i=0; i < ctx->func->arg_cnt; i++)
+            VariantClear(ctx->args+i);
+    }
+
+    heap_free(ctx->args);
+    heap_free(ctx->stack);
+}
+
 HRESULT exec_script(script_ctx_t *ctx, function_t *func, DISPPARAMS *dp, VARIANT *res)
 {
-    exec_ctx_t exec;
+    exec_ctx_t exec = {func->code_ctx};
     vbsop_t op;
     HRESULT hres = S_OK;
 
@@ -822,18 +846,50 @@ HRESULT exec_script(script_ctx_t *ctx, function_t *func, DISPPARAMS *dp, VARIANT
         return E_NOTIMPL;
     }
 
-    if(dp && arg_cnt(dp)) {
-        FIXME("arguments not implemented\n");
-        return E_NOTIMPL;
+    exec.code = func->code_ctx;
+
+    if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
+        FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
+        return E_FAIL;
+    }
+
+    if(func->arg_cnt) {
+        VARIANT *v;
+        unsigned i;
+
+        exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
+        if(!exec.args) {
+            release_exec(&exec);
+            return E_OUTOFMEMORY;
+        }
+
+        for(i=0; i < func->arg_cnt; i++) {
+            v = get_arg(dp, i);
+            if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
+                if(func->args[i].by_ref)
+                    exec.args[i] = *v;
+                else
+                    hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
+            }else {
+                hres = VariantCopy(exec.args+i, v);
+            }
+            if(FAILED(hres)) {
+                release_exec(&exec);
+                return hres;
+            }
+        }
+    }else {
+        exec.args = NULL;
     }
 
     exec.stack_size = 16;
     exec.top = 0;
     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
-    if(!exec.stack)
+    if(!exec.stack) {
+        release_exec(&exec);
         return E_OUTOFMEMORY;
+    }
 
-    exec.code = func->code_ctx;
     exec.instr = exec.code->instrs + func->code_off;
     exec.script = ctx;
     exec.func = func;
@@ -851,7 +907,7 @@ HRESULT exec_script(script_ctx_t *ctx, function_t *func, DISPPARAMS *dp, VARIANT
     }
 
     assert(!exec.top);
-    heap_free(exec.stack);
+    release_exec(&exec);
 
     return hres;
 }
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 0e6d57e..1362d9e 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -70,6 +70,11 @@ static inline unsigned arg_cnt(const DISPPARAMS *dp)
     return dp->cArgs - dp->cNamedArgs;
 }
 
+static inline VARIANT *get_arg(DISPPARAMS *dp, DWORD i)
+{
+    return dp->rgvarg + dp->cArgs-i-1;
+}
+
 typedef struct _dynamic_var_t {
     struct _dynamic_var_t *next;
     VARIANT v;

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 08/21] vbscript: Added sub argument tests
Message-Id: <4E70888A.5070006 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:57:14 +0200

---
  dlls/vbscript/tests/lang.vbs |   42 
++++++++++++++++++++++++++++++++++++++++++
  1 files changed, 42 insertions(+), 0 deletions(-)

diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 0c4c10f..100f93b 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -179,4 +179,46 @@ x = false
 Call testsub
 Call ok(x, "x is false, testsub not called?")
 
+Sub SubSetTrue(v)
+    Call ok(not v, "v is not true")
+    v = true
+End Sub
+
+x = false
+SubSetTrue x
+Call ok(x, "x was not set by SubSetTrue")
+
+SubSetTrue false
+Call ok(not false, "false is no longer false?")
+
+Sub SubSetTrue2(ByRef v)
+    Call ok(not v, "v is not true")
+    v = true
+End Sub
+
+x = false
+SubSetTrue2 x
+Call ok(x, "x was not set by SubSetTrue")
+
+Sub TestSubArgVal(ByVal v)
+    Call ok(not v, "v is not false")
+    v = true
+    Call ok(v, "v is not true?")
+End Sub
+
+x = false
+Call TestSubArgVal(x)
+Call ok(not x, "x is true after TestSubArgVal call?")
+
+Sub TestSubMultiArgs(a,b,c,d,e)
+    Call ok(a=1, "a = " & a)
+    Call ok(b=2, "b = " & b)
+    Call ok(c=3, "c = " & c)
+    Call ok(d=4, "d = " & d)
+    Call ok(e=5, "e = " & e)
+End Sub
+
+TestSubMultiArgs 1, 2, 3, 4, 5
+Call TestSubMultiArgs(1, 2, 3, 4, 5)
+
 reportSuccess()

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 09/21] vbscript: Added exit sub statement implementation
Message-Id: <4E708897.9000303 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:57:27 +0200

---
  dlls/vbscript/compile.c      |   30 ++++++++++++++++++++++++++++++
  dlls/vbscript/parse.h        |    1 +
  dlls/vbscript/parser.y       |    6 ++++--
  dlls/vbscript/tests/lang.vbs |    9 +++++++++
  4 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index bdff74d..f5f7f53 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -38,6 +38,8 @@ typedef struct {
     unsigned labels_size;
     unsigned labels_cnt;
 
+    unsigned sub_end_label;
+
     dim_decl_t *dim_decls;
     dynamic_var_t *global_vars;
 
@@ -530,6 +532,16 @@ static HRESULT compile_function_statement(compile_ctx_t *ctx, function_statement
     return S_OK;
 }
 
+static HRESULT compile_exitsub_statement(compile_ctx_t *ctx)
+{
+    if(ctx->sub_end_label == -1) {
+        FIXME("Exit Sub outside Sub?\n");
+        return E_FAIL;
+    }
+
+    return push_instr_addr(ctx, OP_jmp, ctx->sub_end_label);
+}
+
 static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
 {
     HRESULT hres;
@@ -545,6 +557,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
         case STAT_DIM:
             hres = compile_dim_statement(ctx, (dim_statement_t*)stat);
             break;
+        case STAT_EXITSUB:
+            hres = compile_exitsub_statement(ctx);
+            break;
         case STAT_FUNC:
             hres = compile_function_statement(ctx, (function_statement_t*)stat);
             break;
@@ -585,6 +600,18 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f
 
     func->code_off = ctx->instr_cnt;
 
+    ctx->sub_end_label = -1;
+
+    switch(func->type) {
+    case FUNC_SUB:
+        ctx->sub_end_label = alloc_label(ctx);
+        if(ctx->sub_end_label == -1)
+            return E_OUTOFMEMORY;
+        break;
+    case FUNC_GLOBAL:
+        break;
+    }
+
     ctx->func = func;
     ctx->dim_decls = NULL;
     hres = compile_statement(ctx, stat);
@@ -592,6 +619,9 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f
     if(FAILED(hres))
         return hres;
 
+    if(ctx->sub_end_label != -1)
+        label_set_addr(ctx, ctx->sub_end_label);
+
     if(push_instr(ctx, OP_ret) == -1)
         return E_OUTOFMEMORY;
 
diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index 9b837c2..69eca61 100644
--- a/dlls/vbscript/parse.h
+++ b/dlls/vbscript/parse.h
@@ -86,6 +86,7 @@ typedef enum {
     STAT_ASSIGN,
     STAT_CALL,
     STAT_DIM,
+    STAT_EXITSUB,
     STAT_FUNC,
     STAT_IF
 } statement_type_t;
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index 4964d71..f406f8e 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -45,6 +45,7 @@ static expression_t *new_binary_expression(parser_ctx_t*,expression_type_t,expre
 
 static member_expression_t *new_member_expression(parser_ctx_t*,expression_t*,const WCHAR*);
 
+static void *new_statement(parser_ctx_t*,statement_type_t,size_t);
 static statement_t *new_call_statement(parser_ctx_t*,member_expression_t*);
 static statement_t *new_assign_statement(parser_ctx_t*,member_expression_t*,expression_t*);
 static statement_t *new_dim_statement(parser_ctx_t*,dim_decl_t*);
@@ -138,6 +139,7 @@ Statement
     | tDIM DimDeclList                      { $$ = new_dim_statement(ctx, $2); CHECK_ERROR; }
     | IfStatement                           { $$ = $1; }
     | FunctionDecl                          { $$ = new_function_statement(ctx, $1); CHECK_ERROR; }
+    | tEXIT tSUB                            { $$ = new_statement(ctx, STAT_EXITSUB, 0); CHECK_ERROR; }
 
 MemberExpression
     : tIdentifier                           { $$ = new_member_expression(ctx, NULL, $1); CHECK_ERROR; }
@@ -388,11 +390,11 @@ static member_expression_t *new_member_expression(parser_ctx_t *ctx, expression_
     return expr;
 }
 
-static void *new_statement(parser_ctx_t *ctx, statement_type_t type, unsigned size)
+static void *new_statement(parser_ctx_t *ctx, statement_type_t type, size_t size)
 {
     statement_t *stat;
 
-    stat = parser_alloc(ctx, size);
+    stat = parser_alloc(ctx, size ? size : sizeof(*stat));
     if(stat) {
         stat->type = type;
         stat->next = NULL;
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 100f93b..1140326 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -218,6 +218,15 @@ Sub TestSubMultiArgs(a,b,c,d,e)
     Call ok(e=5, "e = " & e)
 End Sub
 
+Sub TestSubExit(ByRef a)
+    If a Then
+        Exit Sub
+    End If
+    Call ok(false, "Exit Sub not called?")
+End Sub
+
+Call TestSubExit(true)
+
 TestSubMultiArgs 1, 2, 3, 4, 5
 Call TestSubMultiArgs(1, 2, 3, 4, 5)
 

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 10/21] vbscript: Added support for sub local variables
Message-Id: <4E7088A1.9030200 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:57:37 +0200

---
  dlls/vbscript/compile.c      |   37 ++++++++++++++++++++++++++++++++++---
  dlls/vbscript/interp.c       |   29 +++++++++++++++++++++++++++--
  dlls/vbscript/tests/lang.vbs |   11 +++++++++++
  dlls/vbscript/vbscript.h     |    6 ++++++
  4 files changed, 78 insertions(+), 5 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index f5f7f53..725d74d 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -500,12 +500,24 @@ static BOOL lookup_dim_decls(compile_ctx_t *ctx, const WCHAR *name)
     return FALSE;
 }
 
+static BOOL lookup_args_name(compile_ctx_t *ctx, const WCHAR *name)
+{
+    unsigned i;
+
+    for(i = 0; i < ctx->func->arg_cnt; i++) {
+        if(!strcmpiW(ctx->func->args[i].name, name))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
 static HRESULT compile_dim_statement(compile_ctx_t *ctx, dim_statement_t *stat)
 {
     dim_decl_t *dim_decl = stat->dim_decls;
 
     while(1) {
-        if(lookup_dim_decls(ctx, dim_decl->name)) {
+        if(lookup_dim_decls(ctx, dim_decl->name) || lookup_args_name(ctx, dim_decl->name)) {
             FIXME("dim %s name redefined\n", debugstr_w(dim_decl->name));
             return E_FAIL;
         }
@@ -517,6 +529,7 @@ static HRESULT compile_dim_statement(compile_ctx_t *ctx, dim_statement_t *stat)
 
     dim_decl->next = ctx->dim_decls;
     ctx->dim_decls = stat->dim_decls;
+    ctx->func->var_cnt++;
     return S_OK;
 }
 
@@ -627,12 +640,14 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f
 
     resolve_labels(ctx, func->code_off);
 
-    if(ctx->dim_decls) {
+    if(func->var_cnt) {
         dim_decl_t *dim_decl;
 
         if(func->type == FUNC_GLOBAL) {
             dynamic_var_t *new_var;
 
+            func->var_cnt = 0;
+
             for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) {
                 new_var = compiler_alloc(ctx->code, sizeof(*new_var));
                 if(!new_var)
@@ -648,7 +663,19 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f
                 ctx->global_vars = new_var;
             }
         }else {
-            FIXME("var not implemented for functions\n");
+            unsigned i;
+
+            func->vars = compiler_alloc(ctx->code, func->var_cnt * sizeof(var_desc_t));
+            if(!func->vars)
+                return E_OUTOFMEMORY;
+
+            for(dim_decl = ctx->dim_decls, i=0; dim_decl; dim_decl = dim_decl->next, i++) {
+                func->vars[i].name = compiler_alloc_string(ctx->code, dim_decl->name);
+                if(!func->vars[i].name)
+                    return E_OUTOFMEMORY;
+            }
+
+            assert(i == func->var_cnt);
         }
     }
 
@@ -685,6 +712,8 @@ static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, functi
     if(!func->name)
         return E_OUTOFMEMORY;
 
+    func->vars = NULL;
+    func->var_cnt = 0;
     func->code_ctx = ctx->code;
     func->type = decl->type;
 
@@ -808,6 +837,8 @@ static vbscode_t *alloc_vbscode(compile_ctx_t *ctx, const WCHAR *source)
     ret->global_code.type = FUNC_GLOBAL;
     ret->global_code.name = NULL;
     ret->global_code.code_ctx = ret;
+    ret->global_code.vars = NULL;
+    ret->global_code.var_cnt = 0;
     ret->global_code.arg_cnt = 0;
     ret->global_code.args = NULL;
 
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index 68fb4ed..ee77575 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -32,6 +32,7 @@ typedef struct {
     function_t *func;
 
     VARIANT *args;
+    VARIANT *vars;
 
     unsigned stack_size;
     unsigned top;
@@ -88,6 +89,14 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, ref_t *ref)
     DISPID id;
     HRESULT hres;
 
+    for(i=0; i < ctx->func->var_cnt; i++) {
+        if(!strcmpiW(ctx->func->vars[i].name, name)) {
+            ref->type = REF_VAR;
+            ref->u.v = ctx->vars+i;
+            return TRUE;
+        }
+    }
+
     for(i=0; i < ctx->func->arg_cnt; i++) {
         if(!strcmpiW(ctx->func->args[i].name, name)) {
             ref->type = REF_VAR;
@@ -824,14 +833,20 @@ OP_LIST
 
 static void release_exec(exec_ctx_t *ctx)
 {
-    if(ctx->args) {
-        unsigned i;
+    unsigned i;
 
+    if(ctx->args) {
         for(i=0; i < ctx->func->arg_cnt; i++)
             VariantClear(ctx->args+i);
     }
 
+    if(ctx->vars) {
+        for(i=0; i < ctx->func->var_cnt; i++)
+            VariantClear(ctx->vars+i);
+    }
+
     heap_free(ctx->args);
+    heap_free(ctx->vars);
     heap_free(ctx->stack);
 }
 
@@ -882,6 +897,16 @@ HRESULT exec_script(script_ctx_t *ctx, function_t *func, DISPPARAMS *dp, VARIANT
         exec.args = NULL;
     }
 
+    if(func->var_cnt) {
+        exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
+        if(!exec.vars) {
+            release_exec(&exec);
+            return E_OUTOFMEMORY;
+        }
+    }else {
+        exec.vars = NULL;
+    }
+
     exec.stack_size = 16;
     exec.top = 0;
     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 1140326..a46394b 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -230,4 +230,15 @@ Call TestSubExit(true)
 TestSubMultiArgs 1, 2, 3, 4, 5
 Call TestSubMultiArgs(1, 2, 3, 4, 5)
 
+Sub TestSubLocalVal
+    x = false
+    Call ok(not x, "local x is not false?")
+    Dim x
+End Sub
+
+x = true
+y = true
+Call TestSubLocalVal
+Call ok(x, "global x is not true?")
+
 reportSuccess()
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 1362d9e..cf625cc 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -167,11 +167,17 @@ typedef enum {
     FUNC_SUB
 } function_type_t;
 
+typedef struct {
+    const WCHAR *name;
+} var_desc_t;
+
 struct _function_t {
     function_type_t type;
     const WCHAR *name;
     arg_desc_t *args;
     unsigned arg_cnt;
+    var_desc_t *vars;
+    unsigned var_cnt;
     unsigned code_off;
     vbscode_t *code_ctx;
     function_t *next;

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 11/21] vbscript: Added function parser implementation
Message-Id: <4E7088B7.7050603 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:57:59 +0200

---
  dlls/vbscript/compile.c        |    1 +
  dlls/vbscript/parser.y         |    2 +
  dlls/vbscript/tests/lang.vbs   |   63 
++++++++++++++++++++++++++++++++++++++++
  dlls/vbscript/tests/vbscript.c |    3 --
  dlls/vbscript/vbscript.h       |    1 +
  5 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index 725d74d..744a038 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -621,6 +621,7 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f
         if(ctx->sub_end_label == -1)
             return E_OUTOFMEMORY;
         break;
+    case FUNC_FUNCTION: /* FIXME */
     case FUNC_GLOBAL:
         break;
     }
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index f406f8e..36edc02 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -253,6 +253,8 @@ PrimaryExpression
 FunctionDecl
     : /* Storage_opt */ tSUB tIdentifier ArgumentsDecl_opt tNL StatementsNl_opt tEND tSUB
                                     { $$ = new_function_decl(ctx, $2, FUNC_SUB, $3, $5); CHECK_ERROR; }
+    | /* Storage_opt */ tFUNCTION tIdentifier ArgumentsDecl_opt tNL StatementsNl_opt tEND tFUNCTION
+                                    { $$ = new_function_decl(ctx, $2, FUNC_FUNCTION, $3, $5); CHECK_ERROR; }
 
 ArgumentsDecl_opt
     : EmptyBrackets_opt                         { $$ = NULL; }
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index a46394b..5f47360 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -241,4 +241,67 @@ y = true
 Call TestSubLocalVal
 Call ok(x, "global x is not true?")
 
+if false then
+Function testfunc
+    x = true
+End Function
+end if
+
+x = false
+Call TestFunc
+Call ok(x, "x is false, testfunc not called?")
+
+Function FuncSetTrue(v)
+    Call ok(not v, "v is not true")
+    v = true
+End Function
+
+x = false
+FuncSetTrue x
+Call ok(x, "x was not set by FuncSetTrue")
+
+FuncSetTrue false
+Call ok(not false, "false is no longer false?")
+
+Function FuncSetTrue2(ByRef v)
+    Call ok(not v, "v is not true")
+    v = true
+End Function
+
+x = false
+FuncSetTrue2 x
+Call ok(x, "x was not set by FuncSetTrue")
+
+Function TestFuncArgVal(ByVal v)
+    Call ok(not v, "v is not false")
+    v = true
+    Call ok(v, "v is not true?")
+End Function
+
+x = false
+Call TestFuncArgVal(x)
+Call ok(not x, "x is true after TestFuncArgVal call?")
+
+Function TestFuncMultiArgs(a,b,c,d,e)
+    Call ok(a=1, "a = " & a)
+    Call ok(b=2, "b = " & b)
+    Call ok(c=3, "c = " & c)
+    Call ok(d=4, "d = " & d)
+    Call ok(e=5, "e = " & e)
+End Function
+
+TestFuncMultiArgs 1, 2, 3, 4, 5
+Call TestFuncMultiArgs(1, 2, 3, 4, 5)
+
+Function TestFuncLocalVal
+    x = false
+    Call ok(not x, "local x is not false?")
+    Dim x
+End Function
+
+x = true
+y = true
+Call TestFuncLocalVal
+Call ok(x, "global x is not true?")
+
 reportSuccess()
diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c
index ab5c8af..6ead8f4 100644
--- a/dlls/vbscript/tests/vbscript.c
+++ b/dlls/vbscript/tests/vbscript.c
@@ -412,7 +412,6 @@ static void test_vbscript_uninitializing(void)
     test_state(script, SCRIPTSTATE_INITIALIZED);
 
     hres = IActiveScriptParse64_ParseScriptText(parse, script_textW, NULL, NULL, NULL, 0, 1, 0x42, NULL, NULL);
-    todo_wine
     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
 
     hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
@@ -441,9 +440,7 @@ static void test_vbscript_uninitializing(void)
     hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_CONNECTED);
     ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hres);
     CHECK_CALLED(OnStateChange_CONNECTED);
-    todo_wine
     CHECK_CALLED(OnEnterScript);
-    todo_wine
     CHECK_CALLED(OnLeaveScript);
 
     test_state(script, SCRIPTSTATE_CONNECTED);
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index cf625cc..5e86176 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -164,6 +164,7 @@ typedef struct {
 
 typedef enum {
     FUNC_GLOBAL,
+    FUNC_FUNCTION,
     FUNC_SUB
 } function_type_t;
 

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 12/21] vbscript: Added Exit Function statement implementation
Message-Id: <4E7088C2.4070605 at codeweavers.com>
Date: Wed, 14 Sep 2011 12:58:10 +0200

---
  dlls/vbscript/compile.c      |   23 ++++++++++++++++++++++-
  dlls/vbscript/parse.h        |    1 +
  dlls/vbscript/parser.y       |    1 +
  dlls/vbscript/tests/lang.vbs |    9 +++++++++
  4 files changed, 33 insertions(+), 1 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index 744a038..310d7bd 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -39,6 +39,7 @@ typedef struct {
     unsigned labels_cnt;
 
     unsigned sub_end_label;
+    unsigned func_end_label;
 
     dim_decl_t *dim_decls;
     dynamic_var_t *global_vars;
@@ -555,6 +556,16 @@ static HRESULT compile_exitsub_statement(compile_ctx_t *ctx)
     return push_instr_addr(ctx, OP_jmp, ctx->sub_end_label);
 }
 
+static HRESULT compile_exitfunc_statement(compile_ctx_t *ctx)
+{
+    if(ctx->func_end_label == -1) {
+        FIXME("Exit Function outside Function?\n");
+        return E_FAIL;
+    }
+
+    return push_instr_addr(ctx, OP_jmp, ctx->func_end_label);
+}
+
 static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
 {
     HRESULT hres;
@@ -570,6 +581,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
         case STAT_DIM:
             hres = compile_dim_statement(ctx, (dim_statement_t*)stat);
             break;
+        case STAT_EXITFUNC:
+            hres = compile_exitfunc_statement(ctx);
+            break;
         case STAT_EXITSUB:
             hres = compile_exitsub_statement(ctx);
             break;
@@ -614,14 +628,19 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f
     func->code_off = ctx->instr_cnt;
 
     ctx->sub_end_label = -1;
+    ctx->func_end_label = -1;
 
     switch(func->type) {
+    case FUNC_FUNCTION:
+        ctx->func_end_label = alloc_label(ctx);
+        if(ctx->func_end_label == -1)
+            return E_OUTOFMEMORY; /* FIXME ! */
+        break;
     case FUNC_SUB:
         ctx->sub_end_label = alloc_label(ctx);
         if(ctx->sub_end_label == -1)
             return E_OUTOFMEMORY;
         break;
-    case FUNC_FUNCTION: /* FIXME */
     case FUNC_GLOBAL:
         break;
     }
@@ -635,6 +654,8 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f
 
     if(ctx->sub_end_label != -1)
         label_set_addr(ctx, ctx->sub_end_label);
+    if(ctx->func_end_label != -1)
+        label_set_addr(ctx, ctx->func_end_label);
 
     if(push_instr(ctx, OP_ret) == -1)
         return E_OUTOFMEMORY;
diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index 69eca61..6406fc2 100644
--- a/dlls/vbscript/parse.h
+++ b/dlls/vbscript/parse.h
@@ -86,6 +86,7 @@ typedef enum {
     STAT_ASSIGN,
     STAT_CALL,
     STAT_DIM,
+    STAT_EXITFUNC,
     STAT_EXITSUB,
     STAT_FUNC,
     STAT_IF
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index 36edc02..870a665 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -139,6 +139,7 @@ Statement
     | tDIM DimDeclList                      { $$ = new_dim_statement(ctx, $2); CHECK_ERROR; }
     | IfStatement                           { $$ = $1; }
     | FunctionDecl                          { $$ = new_function_statement(ctx, $1); CHECK_ERROR; }
+    | tEXIT tFUNCTION                       { $$ = new_statement(ctx, STAT_EXITFUNC, 0); CHECK_ERROR; }
     | tEXIT tSUB                            { $$ = new_statement(ctx, STAT_EXITSUB, 0); CHECK_ERROR; }
 
 MemberExpression
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 5f47360..93af6b6 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -304,4 +304,13 @@ y = true
 Call TestFuncLocalVal
 Call ok(x, "global x is not true?")
 
+Function TestFuncExit(ByRef a)
+    If a Then
+        Exit Function
+    End If
+    Call ok(false, "Exit Function not called?")
+End Function
+
+Call TestFuncExit(true)
+
 reportSuccess()



More information about the wine-tests-results mailing list