From: Jacek Caban Subject: [PATCH 01/13] vbscript: Added for..to statement parser implementation Message-Id: <4E7B2890.4010807@codeweavers.com> Date: Thu, 22 Sep 2011 14:22:40 +0200 --- dlls/vbscript/lex.c | 6 ++++++ dlls/vbscript/parse.h | 10 ++++++++++ dlls/vbscript/parser.y | 28 ++++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index f42d2fd..ac3d65e 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -44,6 +44,7 @@ static const WCHAR errorW[] = {'e','r','r','o','r',0}; static const WCHAR exitW[] = {'e','x','i','t',0}; static const WCHAR explicitW[] = {'e','x','p','l','i','c','i','t',0}; static const WCHAR falseW[] = {'f','a','l','s','e',0}; +static const WCHAR forW[] = {'f','o','r',0}; static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0}; static const WCHAR getW[] = {'g','e','t',0}; static const WCHAR gotoW[] = {'g','o','t','o',0}; @@ -68,9 +69,11 @@ static const WCHAR publicW[] = {'p','u','b','l','i','c',0}; static const WCHAR remW[] = {'r','e','m',0}; static const WCHAR resumeW[] = {'r','e','s','u','m','e',0}; static const WCHAR setW[] = {'s','e','t',0}; +static const WCHAR stepW[] = {'s','t','e','p',0}; static const WCHAR stopW[] = {'s','t','o','p',0}; static const WCHAR subW[] = {'s','u','b',0}; static const WCHAR thenW[] = {'t','h','e','n',0}; +static const WCHAR toW[] = {'t','o',0}; static const WCHAR trueW[] = {'t','r','u','e',0}; static const WCHAR untilW[] = {'u','n','t','i','l',0}; static const WCHAR wendW[] = {'w','e','n','d',0}; @@ -99,6 +102,7 @@ static const struct { {exitW, tEXIT}, {explicitW, tEXPLICIT}, {falseW, tFALSE}, + {forW, tFOR}, {functionW, tFUNCTION}, {getW, tGET}, {gotoW, tGOTO}, @@ -123,9 +127,11 @@ static const struct { {remW, tREM}, {resumeW, tRESUME}, {setW, tSET}, + {stepW, tSTEP}, {stopW, tSTOP}, {subW, tSUB}, {thenW, tTHEN}, + {toW, tTO}, {trueW, tTRUE}, {untilW, tUNTIL}, {wendW, tWEND}, diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h index 8e4be57..a5bd505 100644 --- a/dlls/vbscript/parse.h +++ b/dlls/vbscript/parse.h @@ -106,6 +106,7 @@ typedef enum { STAT_EXITFUNC, STAT_EXITPROP, STAT_EXITSUB, + STAT_FORTO, STAT_FUNC, STAT_IF, STAT_ONERROR, @@ -198,6 +199,15 @@ typedef struct { typedef struct { statement_t stat; + const WCHAR *identifier; + expression_t *from_expr; + expression_t *to_expr; + expression_t *step_expr; + statement_t *body; +} forto_statement_t; + +typedef struct { + statement_t stat; BOOL resume_next; } onerror_statement_t; diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index 8435e92..3b30051 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -52,6 +52,7 @@ static statement_t *new_assign_statement(parser_ctx_t*,member_expression_t*,expr static statement_t *new_set_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_while_statement(parser_ctx_t*,statement_type_t,expression_t*,statement_t*); +static statement_t *new_forto_statement(parser_ctx_t*,const WCHAR*,expression_t*,expression_t*,expression_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 statement_t *new_onerror_statement(parser_ctx_t*,BOOL); @@ -102,7 +103,7 @@ static statement_t *link_statements(statement_t*,statement_t*); %token tIS tLTEQ tGTEQ tMOD %token tCALL tDIM tSUB tFUNCTION tPROPERTY tGET tLET tCONST %token tIF tELSE tELSEIF tEND tTHEN tEXIT -%token tWHILE tWEND tDO tLOOP tUNTIL +%token tWHILE tWEND tDO tLOOP tUNTIL tFOR tTO tSTEP %token tBYREF tBYVAL %token tOPTION tEXPLICIT %token tSTOP @@ -118,7 +119,7 @@ static statement_t *link_statements(statement_t*,statement_t*); %type ConcatExpression AdditiveExpression ModExpression IntdivExpression MultiplicativeExpression ExpExpression %type NotExpression UnaryExpression AndExpression OrExpression XorExpression EqvExpression %type MemberExpression -%type Arguments_opt ArgumentList_opt ArgumentList +%type Arguments_opt ArgumentList_opt ArgumentList Step_opt %type OptionExplicit_opt DoType %type ArgumentsDecl_opt ArgumentDeclList ArgumentDecl %type FunctionDecl PropertyDecl @@ -186,6 +187,8 @@ SimpleStatement | tON tERROR tRESUME tNEXT { $$ = new_onerror_statement(ctx, TRUE); CHECK_ERROR; } | tON tERROR tGOTO '0' { $$ = new_onerror_statement(ctx, FALSE); CHECK_ERROR; } | tCONST ConstDeclList { $$ = new_const_statement(ctx, $2); CHECK_ERROR; } + | tFOR tIdentifier '=' Expression tTO Expression Step_opt tNL StatementsNl_opt tNEXT + { $$ = new_forto_statement(ctx, $2, $4, $6, $7, $9); CHECK_ERROR; } MemberExpression : tIdentifier { $$ = new_member_expression(ctx, NULL, $1); CHECK_ERROR; } @@ -206,6 +209,10 @@ DoType : tWHILE { $$ = TRUE; } | tUNTIL { $$ = FALSE; } +Step_opt + : /* empty */ { $$ = NULL;} + | tSTEP Expression { $$ = $2; } + IfStatement : tIF Expression tTHEN tNL StatementsNl ElseIfs_opt Else_opt tEND tIF { $$ = new_if_statement(ctx, $2, $5, $6, $7); CHECK_ERROR; } @@ -626,6 +633,23 @@ static statement_t *new_while_statement(parser_ctx_t *ctx, statement_type_t type return &stat->stat; } +static statement_t *new_forto_statement(parser_ctx_t *ctx, const WCHAR *identifier, expression_t *from_expr, + expression_t *to_expr, expression_t *step_expr, statement_t *body) +{ + forto_statement_t *stat; + + stat = new_statement(ctx, STAT_FORTO, sizeof(*stat)); + if(!stat) + return NULL; + + stat->identifier = identifier; + stat->from_expr = from_expr; + stat->to_expr = to_expr; + stat->step_expr = step_expr; + stat->body = body; + return &stat->stat; +} + static statement_t *new_if_statement(parser_ctx_t *ctx, expression_t *expr, statement_t *if_stat, elseif_decl_t *elseif_decl, statement_t *else_stat) { From: Jacek Caban Subject: [PATCH 02/13] vbscript: Added for..to statement compiler implementation Message-Id: <4E7B28AE.2010305@codeweavers.com> Date: Thu, 22 Sep 2011 14:23:10 +0200 --- dlls/vbscript/compile.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++ dlls/vbscript/interp.c | 30 ++++++++++++++++++ dlls/vbscript/vbscript.h | 4 ++ 3 files changed, 111 insertions(+), 0 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 9cfe45b..1f1f041 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -169,6 +169,18 @@ static HRESULT push_instr_int(compile_ctx_t *ctx, vbsop_t op, LONG arg) return S_OK; } +static HRESULT push_instr_uint(compile_ctx_t *ctx, vbsop_t op, unsigned arg) +{ + unsigned ret; + + ret = push_instr(ctx, op); + if(ret == -1) + return E_OUTOFMEMORY; + + instr_ptr(ctx, ret)->arg1.uint = arg; + return S_OK; +} + static HRESULT push_instr_addr(compile_ctx_t *ctx, vbsop_t op, unsigned arg) { unsigned ret; @@ -603,6 +615,68 @@ static HRESULT compile_dowhile_statement(compile_ctx_t *ctx, while_statement_t * return S_OK; } +static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *stat) +{ + unsigned step_instr, instr; + BSTR identifier; + HRESULT hres; + + identifier = alloc_bstr_arg(ctx, stat->identifier); + if(!identifier) + return E_OUTOFMEMORY; + + hres = compile_expression(ctx, stat->from_expr); + if(FAILED(hres)) + return hres; + + instr = push_instr(ctx, OP_assign_ident); + if(instr == -1) + return E_OUTOFMEMORY; + instr_ptr(ctx, instr)->arg1.bstr = identifier; + + hres = compile_expression(ctx, stat->to_expr); + if(FAILED(hres)) + return hres; + + if(push_instr(ctx, OP_val) == -1) + return E_OUTOFMEMORY; + + if(stat->step_expr) { + hres = compile_expression(ctx, stat->step_expr); + if(FAILED(hres)) + return hres; + + if(push_instr(ctx, OP_val) == -1) + return E_OUTOFMEMORY; + }else { + hres = push_instr_int(ctx, OP_short, 1); + if(FAILED(hres)) + return hres; + } + + step_instr = push_instr(ctx, OP_step); + if(step_instr == -1) + return E_OUTOFMEMORY; + instr_ptr(ctx, step_instr)->arg2.bstr = identifier; + + hres = compile_statement(ctx, stat->body); + if(FAILED(hres)) + return hres; + + instr = push_instr(ctx, OP_incc); + if(instr == -1) + return E_OUTOFMEMORY; + instr_ptr(ctx, instr)->arg1.bstr = identifier; + + hres = push_instr_addr(ctx, OP_jmp, step_instr); + if(FAILED(hres)) + return hres; + + instr_ptr(ctx, step_instr)->arg1.uint = ctx->instr_cnt; + + return push_instr_uint(ctx, OP_pop, 2); +} + static HRESULT compile_assign_statement(compile_ctx_t *ctx, assign_statement_t *stat, BOOL is_set) { HRESULT hres; @@ -799,6 +873,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat) case STAT_EXITSUB: hres = compile_exitsub_statement(ctx); break; + case STAT_FORTO: + hres = compile_forto_statement(ctx, (forto_statement_t*)stat); + break; case STAT_FUNC: hres = compile_function_statement(ctx, (function_statement_t*)stat); break; diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index c2ffd98..1327c17 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -682,6 +682,22 @@ static HRESULT interp_const(exec_ctx_t *ctx) return add_dynamic_var(ctx, arg, TRUE, val.v, val.owned); } +static HRESULT interp_val(exec_ctx_t *ctx) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT interp_pop(exec_ctx_t *ctx) +{ + const unsigned n = ctx->instr->arg1.uint; + + TRACE("%u\n", n); + + stack_popn(ctx, n); + return S_OK; +} + static HRESULT interp_new(exec_ctx_t *ctx) { const WCHAR *arg = ctx->instr->arg1.bstr; @@ -710,6 +726,13 @@ static HRESULT interp_new(exec_ctx_t *ctx) return stack_push(ctx, &v); } +static HRESULT interp_step(exec_ctx_t *ctx) +{ + const BSTR ident = ctx->instr->arg2.bstr; + FIXME("%s\n", debugstr_w(ident)); + return E_NOTIMPL; +} + static HRESULT interp_jmp(exec_ctx_t *ctx) { const unsigned arg = ctx->instr->arg1.uint; @@ -1439,6 +1462,13 @@ static HRESULT interp_neg(exec_ctx_t *ctx) return stack_push(ctx, &v); } +static HRESULT interp_incc(exec_ctx_t *ctx) +{ + const BSTR ident = ctx->instr->arg1.bstr; + FIXME("%s\n", debugstr_w(ident)); + return E_NOTIMPL; +} + static const instr_func_t op_funcs[] = { #define X(x,n,a,b) interp_ ## x, OP_LIST diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index bd55719..4b0a569 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -199,6 +199,7 @@ typedef enum { X(icallv, 1, ARG_BSTR, ARG_UINT) \ X(idiv, 1, 0, 0) \ X(imp, 1, 0, 0) \ + X(incc, 1, ARG_BSTR, 0) \ X(is, 1, 0, 0) \ X(jmp, 0, ARG_ADDR, 0) \ X(jmp_false, 0, ARG_ADDR, 0) \ @@ -218,13 +219,16 @@ typedef enum { X(nothing, 1, 0, 0) \ X(null, 1, 0, 0) \ X(or, 1, 0, 0) \ + X(pop, 1, ARG_UINT, 0) \ X(ret, 0, 0, 0) \ X(set_ident, 1, ARG_BSTR, 0) \ X(set_member, 1, ARG_BSTR, 0) \ X(short, 1, ARG_INT, 0) \ + X(step, 0, ARG_ADDR, ARG_BSTR) \ X(stop, 1, 0, 0) \ X(string, 1, ARG_STR, 0) \ X(sub, 1, 0, 0) \ + X(val, 1, 0, 0) \ X(xor, 1, 0, 0) typedef enum { From: Jacek Caban Subject: [PATCH 03/13] vbscript: Added interp_val implementation Message-Id: <4E7B28BD.3090801@codeweavers.com> Date: Thu, 22 Sep 2011 14:23:25 +0200 --- dlls/vbscript/interp.c | 20 ++++++++++++++++++-- 1 files changed, 18 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 1327c17..5e41845 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -684,8 +684,24 @@ static HRESULT interp_const(exec_ctx_t *ctx) static HRESULT interp_val(exec_ctx_t *ctx) { - FIXME("\n"); - return E_NOTIMPL; + variant_val_t val; + VARIANT v; + HRESULT hres; + + TRACE("\n"); + + hres = stack_pop_val(ctx, &val); + if(FAILED(hres)) + return hres; + + if(!val.owned) { + V_VT(&v) = VT_EMPTY; + hres = VariantCopy(&v, val.v); + if(FAILED(hres)) + return hres; + } + + return stack_push(ctx, val.owned ? val.v : &v); } static HRESULT interp_pop(exec_ctx_t *ctx) From: Jacek Caban Subject: [PATCH 04/13] vbscript: Added interp_step implementation Message-Id: <4E7B28D7.3090304@codeweavers.com> Date: Thu, 22 Sep 2011 14:23:51 +0200 --- dlls/vbscript/interp.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 files changed, 39 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 5e41845..c95183d 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -245,6 +245,12 @@ static inline VARIANT *stack_pop(exec_ctx_t *ctx) return ctx->stack + --ctx->top; } +static inline VARIANT *stack_top(exec_ctx_t *ctx, unsigned n) +{ + assert(ctx->top >= n); + return ctx->stack + (ctx->top-n-1); +} + static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v) { if(ctx->stack_size == ctx->top) { @@ -745,8 +751,39 @@ static HRESULT interp_new(exec_ctx_t *ctx) static HRESULT interp_step(exec_ctx_t *ctx) { const BSTR ident = ctx->instr->arg2.bstr; - FIXME("%s\n", debugstr_w(ident)); - return E_NOTIMPL; + BOOL gteq_zero; + VARIANT zero; + ref_t ref; + HRESULT hres; + + TRACE("%s\n", debugstr_w(ident)); + + V_VT(&zero) = VT_I2; + V_I2(&zero) = 0; + hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0); + if(FAILED(hres)) + return hres; + + gteq_zero = hres == VARCMP_GT || hres == VARCMP_EQ; + + hres = lookup_identifier(ctx, ident, VBDISP_ANY, &ref); + if(FAILED(hres)) + return hres; + + if(ref.type != REF_VAR) { + FIXME("%s is not REF_VAR\n", debugstr_w(ident)); + return E_FAIL; + } + + hres = VarCmp(ref.u.v, stack_top(ctx, 1), ctx->script->lcid, 0); + if(FAILED(hres)) + return hres; + + if(hres == VARCMP_EQ || hres == (gteq_zero ? VARCMP_LT : VARCMP_GT)) + ctx->instr++; + else + instr_jmp(ctx, ctx->instr->arg1.uint); + return S_OK; } static HRESULT interp_jmp(exec_ctx_t *ctx) From: Jacek Caban Subject: [PATCH 05/13] vbscript: Added interp_incc implementation Message-Id: <4E7B28E5.8090408@codeweavers.com> Date: Thu, 22 Sep 2011 14:24:05 +0200 --- dlls/vbscript/interp.c | 24 ++++++++++++++++++++++-- 1 files changed, 22 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index c95183d..08ea83e 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1518,8 +1518,28 @@ static HRESULT interp_neg(exec_ctx_t *ctx) static HRESULT interp_incc(exec_ctx_t *ctx) { const BSTR ident = ctx->instr->arg1.bstr; - FIXME("%s\n", debugstr_w(ident)); - return E_NOTIMPL; + VARIANT v; + ref_t ref; + HRESULT hres; + + TRACE("\n"); + + hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref); + if(FAILED(hres)) + return hres; + + if(ref.type != REF_VAR) { + FIXME("ref.type is not REF_VAR\n"); + return E_FAIL; + } + + hres = VarAdd(stack_top(ctx, 0), ref.u.v, &v); + if(FAILED(hres)) + return hres; + + VariantClear(ref.u.v); + *ref.u.v = v; + return S_OK; } static const instr_func_t op_funcs[] = { From: Jacek Caban Subject: [PATCH 06/13] vbscript: Added for..in statement tests Message-Id: <4E7B28F4.3090502@codeweavers.com> Date: Thu, 22 Sep 2011 14:24:20 +0200 --- dlls/vbscript/tests/lang.vbs | 56 +++++++++++++++++++++++++++++++++++++++++- 1 files changed, 55 insertions(+), 1 deletions(-) diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 2d712f5..3b3ad50 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -18,7 +18,7 @@ Option Explicit -dim x, y +dim x, y, z call ok(true, "true is not true?") ok true, "true is not true?" @@ -333,6 +333,60 @@ do ok false, "exit do didn't work" loop while true +y = "for1:" +for x = 5 to 8 + y = y & " " & x +next +Call ok(y = "for1: 5 6 7 8", "y = " & y) + +y = "for2:" +for x = 5 to 8 step 2 + y = y & " " & x +next +Call ok(y = "for2: 5 7", "y = " & y) + +y = "for3:" +x = 2 +for x = x+3 to 8 + y = y & " " & x +next +Call ok(y = "for3: 5 6 7 8", "y = " & y) + +y = "for4:" +for x = 5 to 4 + y = y & " " & x +next +Call ok(y = "for4:", "y = " & y) + +y = "for5:" +for x = 5 to 3 step true + y = y & " " & x +next +Call ok(y = "for5: 5 4 3", "y = " & y) + +y = "for6:" +z = 4 +for x = 5 to z step 3-4 + y = y & " " & x + z = 0 +next +Call ok(y = "for6: 5 4", "y = " & y) + +y = "for7:" +z = 1 +for x = 5 to 8 step z + y = y & " " & x + z = 2 +next +Call ok(y = "for7: 5 6 7 8", "y = " & y) + +y = "for8:" +for x = 5 to 8 + y = y & " " & x + x = x+1 +next +Call ok(y = "for8: 5 7", "y = " & y) + if false then Sub testsub x = true From: Jacek Caban Subject: [PATCH 07/13] vbscript: Added exit for statement support Message-Id: <4E7B290C.6000604@codeweavers.com> Date: Thu, 22 Sep 2011 14:24:44 +0200 --- dlls/vbscript/compile.c | 27 +++++++++++++++++++++++++-- dlls/vbscript/parse.h | 1 + dlls/vbscript/parser.y | 1 + dlls/vbscript/tests/lang.vbs | 9 +++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 1f1f041..153e9b0 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -39,6 +39,7 @@ typedef struct { unsigned labels_cnt; unsigned while_end_label; + unsigned for_end_label; unsigned sub_end_label; unsigned func_end_label; unsigned prop_end_label; @@ -617,7 +618,7 @@ static HRESULT compile_dowhile_statement(compile_ctx_t *ctx, while_statement_t * static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *stat) { - unsigned step_instr, instr; + unsigned step_instr, instr, prev_label; BSTR identifier; HRESULT hres; @@ -654,10 +655,16 @@ static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *st return hres; } + prev_label = ctx->for_end_label; + ctx->for_end_label = alloc_label(ctx); + if(ctx->for_end_label == -1) + return E_OUTOFMEMORY; + step_instr = push_instr(ctx, OP_step); if(step_instr == -1) return E_OUTOFMEMORY; instr_ptr(ctx, step_instr)->arg2.bstr = identifier; + instr_ptr(ctx, step_instr)->arg1.uint = ctx->for_end_label; hres = compile_statement(ctx, stat->body); if(FAILED(hres)) @@ -672,7 +679,8 @@ static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *st if(FAILED(hres)) return hres; - instr_ptr(ctx, step_instr)->arg1.uint = ctx->instr_cnt; + label_set_addr(ctx, ctx->for_end_label); + ctx->for_end_label = prev_label; return push_instr_uint(ctx, OP_pop, 2); } @@ -804,6 +812,16 @@ static HRESULT compile_exitdo_statement(compile_ctx_t *ctx) return push_instr_addr(ctx, OP_jmp, ctx->while_end_label); } +static HRESULT compile_exitfor_statement(compile_ctx_t *ctx) +{ + if(ctx->for_end_label == -1) { + FIXME("Exit For outside For Loop\n"); + return E_FAIL; + } + + return push_instr_addr(ctx, OP_jmp, ctx->for_end_label); +} + static HRESULT compile_exitsub_statement(compile_ctx_t *ctx) { if(ctx->sub_end_label == -1) { @@ -864,6 +882,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat) case STAT_EXITDO: hres = compile_exitdo_statement(ctx); break; + case STAT_EXITFOR: + hres = compile_exitfor_statement(ctx); + break; case STAT_EXITFUNC: hres = compile_exitfunc_statement(ctx); break; @@ -931,6 +952,7 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f func->code_off = ctx->instr_cnt; ctx->while_end_label = -1; + ctx->for_end_label = -1; ctx->sub_end_label = -1; ctx->func_end_label = -1; ctx->prop_end_label = -1; @@ -967,6 +989,7 @@ static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *f return hres; assert(ctx->while_end_label == -1); + assert(ctx->for_end_label == -1); if(ctx->sub_end_label != -1) label_set_addr(ctx, ctx->sub_end_label); diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h index a5bd505..e58e7f3 100644 --- a/dlls/vbscript/parse.h +++ b/dlls/vbscript/parse.h @@ -103,6 +103,7 @@ typedef enum { STAT_DOUNTIL, STAT_DOWHILE, STAT_EXITDO, + STAT_EXITFOR, STAT_EXITFUNC, STAT_EXITPROP, STAT_EXITSUB, diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index 3b30051..d6bda55 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -178,6 +178,7 @@ SimpleStatement CHECK_ERROR; } | FunctionDecl { $$ = new_function_statement(ctx, $1); CHECK_ERROR; } | tEXIT tDO { $$ = new_statement(ctx, STAT_EXITDO, 0); CHECK_ERROR; } + | tEXIT tFOR { $$ = new_statement(ctx, STAT_EXITFOR, 0); CHECK_ERROR; } | tEXIT tFUNCTION { $$ = new_statement(ctx, STAT_EXITFUNC, 0); CHECK_ERROR; } | tEXIT tPROPERTY { $$ = new_statement(ctx, STAT_EXITPROP, 0); CHECK_ERROR; } | tEXIT tSUB { $$ = new_statement(ctx, STAT_EXITSUB, 0); CHECK_ERROR; } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 3b3ad50..46a0330 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -387,6 +387,15 @@ for x = 5 to 8 next Call ok(y = "for8: 5 7", "y = " & y) +for x = 1.5 to 1 + Call ok(false, "for..to called when unexpected") +next + +for x = 1 to 100 + exit for + Call ok(false, "exit for not escaped the loop?") +next + if false then Sub testsub x = true From: Jacek Caban Subject: [PATCH 08/13] vbscript: Added support for DISPATCH_METHOD flags in invoke_builtin Message-Id: <4E7B2922.9070308@codeweavers.com> Date: Thu, 22 Sep 2011 14:25:06 +0200 --- dlls/vbscript/vbdisp.c | 18 +++++++++++++----- 1 files changed, 13 insertions(+), 5 deletions(-) diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 96df71a..d083d74 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -139,14 +139,15 @@ static HRESULT invoke_builtin(vbdisp_t *This, const builtin_prop_t *prop, WORD f FIXME("property does not support DISPATCH_PROPERTYGET\n"); return E_FAIL; } - /* FALLTHROUGH */ + break; case DISPATCH_PROPERTYGET|DISPATCH_METHOD: - if(arg_cnt(dp) < prop->min_args || arg_cnt(dp) > (prop->max_args ? prop->max_args : prop->min_args)) { - FIXME("invalid number of arguments\n"); + break; + case DISPATCH_METHOD: + if(prop->flags & (BP_GET|BP_GETPUT)) { + FIXME("Call on property\n"); return E_FAIL; } - - return prop->proc(This, dp->rgvarg, dp->cArgs, res); + break; case DISPATCH_PROPERTYPUT: if(!(prop->flags & (BP_GET|BP_GETPUT))) { FIXME("property does not support DISPATCH_PROPERTYPUT\n"); @@ -159,6 +160,13 @@ static HRESULT invoke_builtin(vbdisp_t *This, const builtin_prop_t *prop, WORD f FIXME("unsupported flags %x\n", flags); return E_NOTIMPL; } + + if(arg_cnt(dp) < prop->min_args || arg_cnt(dp) > (prop->max_args ? prop->max_args : prop->min_args)) { + FIXME("invalid number of arguments\n"); + return E_FAIL; + } + + return prop->proc(This, dp->rgvarg, dp->cArgs, res); } static BOOL run_terminator(vbdisp_t *This) From: Jacek Caban Subject: [PATCH 09/13] vbscript: Lookup global object before host-provided objects Message-Id: <4E7B292B.6090203@codeweavers.com> Date: Thu, 22 Sep 2011 14:25:15 +0200 --- dlls/vbscript/interp.c | 44 +++++++++++++++++++++++--------------------- 1 files changed, 23 insertions(+), 21 deletions(-) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 08ea83e..678b51a 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -126,12 +126,14 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref)) return S_OK; - hres = disp_get_id(ctx->this_obj, name, invoke_type, TRUE, &id); - if(SUCCEEDED(hres)) { - ref->type = REF_DISP; - ref->u.d.disp = ctx->this_obj; - ref->u.d.id = id; - return S_OK; + if(ctx->func->type != FUNC_GLOBAL) { + hres = disp_get_id(ctx->this_obj, name, invoke_type, TRUE, &id); + if(SUCCEEDED(hres)) { + ref->type = REF_DISP; + ref->u.d.disp = ctx->this_obj; + ref->u.d.id = id; + return S_OK; + } } if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref)) @@ -145,8 +147,22 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } } + if(!strcmpiW(name, errW)) { + ref->type = REF_OBJ; + ref->u.obj = (IDispatch*)&ctx->script->err_obj->IDispatchEx_iface; + return S_OK; + } + + hres = vbdisp_get_id(ctx->script->global_obj, name, invoke_type, TRUE, &id); + if(SUCCEEDED(hres)) { + ref->type = REF_DISP; + ref->u.d.disp = (IDispatch*)&ctx->script->global_obj->IDispatchEx_iface; + ref->u.d.id = id; + return S_OK; + } + LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) { - if((item->flags & SCRIPTITEM_GLOBALMEMBERS) && item->disp != ctx->this_obj) { + if((item->flags & SCRIPTITEM_GLOBALMEMBERS)) { hres = disp_get_id(item->disp, name, invoke_type, FALSE, &id); if(SUCCEEDED(hres)) { ref->type = REF_DISP; @@ -180,20 +196,6 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_ } } - if(!strcmpiW(name, errW)) { - ref->type = REF_OBJ; - ref->u.obj = (IDispatch*)&ctx->script->err_obj->IDispatchEx_iface; - return S_OK; - } - - hres = vbdisp_get_id(ctx->script->global_obj, name, invoke_type, TRUE, &id); - if(SUCCEEDED(hres)) { - ref->type = REF_DISP; - ref->u.d.disp = (IDispatch*)&ctx->script->global_obj->IDispatchEx_iface; - ref->u.d.id = id; - return S_OK; - } - ref->type = REF_NONE; return S_OK; } From: Jacek Caban Subject: [PATCH 10/13] vbscript: Added CreateObject implementation Message-Id: <4E7B2937.4020100@codeweavers.com> Date: Thu, 22 Sep 2011 14:25:27 +0200 --- dlls/vbscript/global.c | 134 ++++++++++++++++++++++++++++++++++++++++- dlls/vbscript/vbscript.c | 3 + dlls/vbscript/vbscript.h | 3 + dlls/vbscript/vbscript_main.c | 1 + 4 files changed, 139 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c index 3d58ea7..5af7e16 100644 --- a/dlls/vbscript/global.c +++ b/dlls/vbscript/global.c @@ -19,10 +19,118 @@ #include "vbscript.h" #include "vbscript_defs.h" +#include "mshtmhst.h" +#include "objsafe.h" + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(vbscript); +#define VB_E_CANNOT_CREATE_OBJ 0x800a01ad + +/* Defined as extern in urlmon.idl, but not exported by uuid.lib */ +const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY = + {0x10200490,0xfa38,0x11d0,{0xac,0x0e,0x00,0xa0,0xc9,0xf,0xff,0xc0}}; + +static IInternetHostSecurityManager *get_sec_mgr(script_ctx_t *ctx) +{ + IInternetHostSecurityManager *secmgr; + IServiceProvider *sp; + HRESULT hres; + + if(!ctx->site) + return NULL; + + if(ctx->secmgr) + return ctx->secmgr; + + hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IServiceProvider, (void**)&sp); + if(FAILED(hres)) + return NULL; + + hres = IServiceProvider_QueryService(sp, &SID_SInternetHostSecurityManager, &IID_IInternetHostSecurityManager, + (void**)&secmgr); + IServiceProvider_Release(sp); + if(FAILED(hres)) + return NULL; + + return ctx->secmgr = secmgr; +} + +static IUnknown *create_object(script_ctx_t *ctx, const WCHAR *progid) +{ + IInternetHostSecurityManager *secmgr = NULL; + IObjectWithSite *obj_site; + struct CONFIRMSAFETY cs; + IClassFactoryEx *cfex; + IClassFactory *cf; + DWORD policy_size; + BYTE *bpolicy; + IUnknown *obj; + DWORD policy; + GUID guid; + HRESULT hres; + + hres = CLSIDFromProgID(progid, &guid); + if(FAILED(hres)) + return NULL; + + TRACE("GUID %s\n", debugstr_guid(&guid)); + + if(ctx->safeopt & INTERFACE_USES_SECURITY_MANAGER) { + secmgr = get_sec_mgr(ctx); + if(!secmgr) + return NULL; + + policy = 0; + hres = IInternetHostSecurityManager_ProcessUrlAction(secmgr, URLACTION_ACTIVEX_RUN, + (BYTE*)&policy, sizeof(policy), (BYTE*)&guid, sizeof(GUID), 0, 0); + if(FAILED(hres) || policy != URLPOLICY_ALLOW) + return NULL; + } + + hres = CoGetClassObject(&guid, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (void**)&cf); + if(FAILED(hres)) + return NULL; + + hres = IClassFactory_QueryInterface(cf, &IID_IClassFactoryEx, (void**)&cfex); + if(SUCCEEDED(hres)) { + FIXME("Use IClassFactoryEx\n"); + IClassFactoryEx_Release(cfex); + } + + hres = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)&obj); + if(FAILED(hres)) + return NULL; + + if(secmgr) { + cs.clsid = guid; + cs.pUnk = obj; + cs.dwFlags = 0; + hres = IInternetHostSecurityManager_QueryCustomPolicy(secmgr, &GUID_CUSTOM_CONFIRMOBJECTSAFETY, + &bpolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0); + if(SUCCEEDED(hres)) { + policy = policy_size >= sizeof(DWORD) ? *(DWORD*)bpolicy : URLPOLICY_DISALLOW; + CoTaskMemFree(bpolicy); + } + + if(FAILED(hres) || policy != URLPOLICY_ALLOW) { + IUnknown_Release(obj); + return NULL; + } + } + + hres = IUnknown_QueryInterface(obj, &IID_IObjectWithSite, (void**)&obj_site); + if(SUCCEEDED(hres)) { + FIXME("ObjectWithSite\n"); + IObjectWithSite_Release(obj_site); + IUnknown_Release(obj); + return NULL; + } + + return obj; +} + static HRESULT Global_CCur(vbdisp_t *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { FIXME("\n"); @@ -483,8 +591,30 @@ static HRESULT Global_MsgBox(vbdisp_t *This, VARIANT *arg, unsigned args_cnt, VA static HRESULT Global_CreateObject(vbdisp_t *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + IUnknown *obj; + HRESULT hres; + + TRACE("(%s)\n", debugstr_variant(arg)); + + if(V_VT(arg) != VT_BSTR) { + FIXME("non-bstr arg\n"); + return E_INVALIDARG; + } + + obj = create_object(This->desc->ctx, V_BSTR(arg)); + if(!obj) + return VB_E_CANNOT_CREATE_OBJ; + + if(res) { + hres = IUnknown_QueryInterface(obj, &IID_IDispatch, (void**)&V_DISPATCH(res)); + if(FAILED(hres)) + return hres; + + V_VT(res) = VT_DISPATCH; + } + + IUnknown_Release(obj); + return S_OK; } static HRESULT Global_GetObject(vbdisp_t *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 3ac9560..d4e8cca 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -129,6 +129,8 @@ static void destroy_script(script_ctx_t *ctx) if(ctx->host_global) IDispatch_Release(ctx->host_global); + if(ctx->secmgr) + IInternetHostSecurityManager_Release(ctx->secmgr); if(ctx->site) IActiveScriptSite_Release(ctx->site); if(ctx->err_obj) @@ -516,6 +518,7 @@ static HRESULT WINAPI VBScriptParse_InitNew(IActiveScriptParse *iface) if(!ctx) return E_OUTOFMEMORY; + ctx->safeopt = This->safeopt; vbsheap_init(&ctx->heap); list_init(&ctx->objects); list_init(&ctx->code_list); diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 4b0a569..d8134fa 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -143,6 +143,9 @@ struct _script_ctx_t { IActiveScriptSite *site; LCID lcid; + IInternetHostSecurityManager *secmgr; + DWORD safeopt; + IDispatch *host_global; class_desc_t script_desc; diff --git a/dlls/vbscript/vbscript_main.c b/dlls/vbscript/vbscript_main.c index 4054d35..c47227f 100644 --- a/dlls/vbscript/vbscript_main.c +++ b/dlls/vbscript/vbscript_main.c @@ -20,6 +20,7 @@ #include "vbscript.h" #include "objsafe.h" +#include "mshtmhst.h" #include "rpcproxy.h" #include "vbscript_classes.h" #include "vbsglobal.h"