#include "vbscript.h"
#include "parse.h"
-//#include "parser.tab.h"
+#include "parser.tab.h"
-#include <wine/debug.h>
+#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
WINE_DECLARE_DEBUG_CHANNEL(vbscript_disas);
unsigned prop_end_label;
dim_decl_t *dim_decls;
+ dim_decl_t *dim_decls_tail;
dynamic_var_t *global_vars;
const_decl_t *const_decls;
ctx->labels[label & ~LABEL_FLAG] = ctx->instr_cnt;
}
+static inline unsigned stack_offset(compile_ctx_t *ctx)
+{
+ statement_ctx_t *iter;
+ unsigned ret = 0;
+
+ for(iter = ctx->stat_ctx; iter; iter = iter->next)
+ ret += iter->stack_use;
+
+ return ret;
+}
+
+static BOOL emit_catch_jmp(compile_ctx_t *ctx, unsigned stack_off, unsigned code_off)
+{
+ unsigned code;
+
+ code = push_instr(ctx, OP_catch);
+ if(!code)
+ return FALSE;
+
+ instr_ptr(ctx, code)->arg1.uint = code_off;
+ instr_ptr(ctx, code)->arg2.uint = stack_off + stack_offset(ctx);
+ return TRUE;
+}
+
+static inline BOOL emit_catch(compile_ctx_t *ctx, unsigned off)
+{
+ return emit_catch_jmp(ctx, off, ctx->instr_cnt);
+}
+
static expression_t *lookup_const_decls(compile_ctx_t *ctx, const WCHAR *name, BOOL lookup_global)
{
const_decl_t *decl;
return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_nequal);
case EXPR_NEW:
return push_instr_str(ctx, OP_new, ((string_expression_t*)expr)->value);
+ case EXPR_NOARG:
+ return push_instr_int(ctx, OP_hres, DISP_E_PARAMNOTFOUND);
case EXPR_NOT:
return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_not);
case EXPR_NOTHING:
if(!cnd_jmp)
return E_OUTOFMEMORY;
+ if(!emit_catch(ctx, 0))
+ return E_OUTOFMEMORY;
+
hres = compile_statement(ctx, NULL, stat->if_stat);
if(FAILED(hres))
return hres;
if(!cnd_jmp)
return E_OUTOFMEMORY;
+ if(!emit_catch(ctx, 0))
+ return E_OUTOFMEMORY;
+
hres = compile_statement(ctx, NULL, elseif_decl->stat);
if(FAILED(hres))
return hres;
if(!jmp_end)
return E_OUTOFMEMORY;
+ if(!emit_catch(ctx, 0))
+ return E_OUTOFMEMORY;
+
if(stat->stat.type == STAT_WHILE) {
loop_ctx = NULL;
}else {
return hres;
label_set_addr(ctx, loop_ctx.while_end_label);
+
+ if(!emit_catch(ctx, 0))
+ return E_OUTOFMEMORY;
+
return S_OK;
}
unsigned loop_start;
HRESULT hres;
+ /* Preserve a place on the stack in case we throw before having proper enum collection. */
+ if(!push_instr(ctx, OP_empty))
+ return E_OUTOFMEMORY;
+
hres = compile_expression(ctx, stat->group_expr);
if(FAILED(hres))
return hres;
if(!push_instr(ctx, OP_newenum))
return E_OUTOFMEMORY;
- loop_start = ctx->instr_cnt;
if(!(loop_ctx.for_end_label = alloc_label(ctx)))
return E_OUTOFMEMORY;
if(FAILED(hres))
return hres;
+ if(!emit_catch(ctx, 1))
+ return E_OUTOFMEMORY;
+
+ loop_start = ctx->instr_cnt;
hres = compile_statement(ctx, &loop_ctx, stat->body);
if(FAILED(hres))
return hres;
+ /* We need a separated enumnext here, because we need to jump out of the loop on exception. */
+ hres = push_instr_uint_bstr(ctx, OP_enumnext, loop_ctx.for_end_label, stat->identifier);
+ if(FAILED(hres))
+ return hres;
+
hres = push_instr_addr(ctx, OP_jmp, loop_start);
if(FAILED(hres))
return hres;
if(FAILED(hres))
return hres;
+ /* FIXME: Assign should happen after both expressions evaluation. */
instr = push_instr(ctx, OP_assign_ident);
if(!instr)
return E_OUTOFMEMORY;
instr_ptr(ctx, step_instr)->arg2.bstr = identifier;
instr_ptr(ctx, step_instr)->arg1.uint = loop_ctx.for_end_label;
+ if(!emit_catch(ctx, 2))
+ return E_OUTOFMEMORY;
+
hres = compile_statement(ctx, &loop_ctx, stat->body);
if(FAILED(hres))
return hres;
+ /* FIXME: Error handling can't be done compatible with native using OP_incc here. */
instr = push_instr(ctx, OP_incc);
if(!instr)
return E_OUTOFMEMORY;
return hres;
label_set_addr(ctx, loop_ctx.for_end_label);
+
+ /* FIXME: reconsider after OP_incc fixup. */
+ if(!emit_catch(ctx, 0))
+ return E_OUTOFMEMORY;
+
return S_OK;
}
if(!end_label)
return E_OUTOFMEMORY;
+ if(!emit_catch_jmp(ctx, 0, end_label))
+ return E_OUTOFMEMORY;
+
for(case_iter = stat->case_clausules; case_iter; case_iter = case_iter->next)
case_cnt++;
hres = push_instr_addr(ctx, OP_case, case_labels[i]);
if(FAILED(hres))
break;
+
+ if(!emit_catch_jmp(ctx, 0, case_labels[i])) {
+ hres = E_OUTOFMEMORY;
+ break;
+ }
}
}
if(FAILED(hres))
return hres;
- return push_instr_bstr_uint(ctx, op, member_expr->identifier, args_cnt);
+ hres = push_instr_bstr_uint(ctx, op, member_expr->identifier, args_cnt);
+ if(FAILED(hres))
+ return hres;
+
+ if(!emit_catch(ctx, 0))
+ return E_OUTOFMEMORY;
+
+ return S_OK;
}
static HRESULT compile_assign_statement(compile_ctx_t *ctx, assign_statement_t *stat, BOOL is_set)
static HRESULT compile_call_statement(compile_ctx_t *ctx, call_statement_t *stat)
{
+ HRESULT hres;
+
/* It's challenging for parser to distinguish parameterized assignment with one argument from call
* with equality expression argument, so we do it in compiler. */
if(!stat->is_strict && stat->expr->args && !stat->expr->args->next && stat->expr->args->type == EXPR_EQUAL) {
}
}
- return compile_member_expression(ctx, stat->expr, FALSE);
+ hres = compile_member_expression(ctx, stat->expr, FALSE);
+ if(FAILED(hres))
+ return hres;
+
+ if(!emit_catch(ctx, 0))
+ return E_OUTOFMEMORY;
+
+ return S_OK;
}
static BOOL lookup_dim_decls(compile_ctx_t *ctx, const WCHAR *name)
}
ctx->func->var_cnt++;
+
+ if(dim_decl->is_array) {
+ HRESULT hres = push_instr_bstr_uint(ctx, OP_dim, dim_decl->name, ctx->func->array_cnt++);
+ if(FAILED(hres))
+ return hres;
+
+ if(!emit_catch(ctx, 0))
+ return E_OUTOFMEMORY;
+ }
+
if(!dim_decl->next)
break;
dim_decl = dim_decl->next;
}
- dim_decl->next = ctx->dim_decls;
- ctx->dim_decls = stat->dim_decls;
+ if(ctx->dim_decls_tail)
+ ctx->dim_decls_tail->next = stat->dim_decls;
+ else
+ ctx->dim_decls = stat->dim_decls;
+ ctx->dim_decls_tail = dim_decl;
return S_OK;
}
hres = push_instr_bstr(ctx, OP_const, decl->name);
if(FAILED(hres))
return hres;
+
+ if(!emit_catch(ctx, 0))
+ return E_OUTOFMEMORY;
}
next_decl = decl->next;
static HRESULT exit_label(compile_ctx_t *ctx, unsigned jmp_label)
{
- statement_ctx_t *iter;
- unsigned pop_cnt = 0;
-
- for(iter = ctx->stat_ctx; iter; iter = iter->next)
- pop_cnt += iter->stack_use;
+ unsigned pop_cnt = stack_offset(ctx);
if(pop_cnt) {
HRESULT hres;
ctx->labels_cnt = 0;
}
+static HRESULT fill_array_desc(compile_ctx_t *ctx, dim_decl_t *dim_decl, array_desc_t *array_desc)
+{
+ unsigned dim_cnt = 0, i;
+ dim_list_t *iter;
+
+ for(iter = dim_decl->dims; iter; iter = iter->next)
+ dim_cnt++;
+
+ array_desc->bounds = compiler_alloc(ctx->code, dim_cnt * sizeof(SAFEARRAYBOUND));
+ if(!array_desc->bounds)
+ return E_OUTOFMEMORY;
+
+ array_desc->dim_cnt = dim_cnt;
+
+ for(iter = dim_decl->dims, i=0; iter; iter = iter->next, i++) {
+ array_desc->bounds[i].cElements = iter->val+1;
+ array_desc->bounds[i].lLbound = 0;
+ }
+
+ return S_OK;
+}
+
static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *func)
{
HRESULT hres;
}
ctx->func = func;
- ctx->dim_decls = NULL;
+ ctx->dim_decls = ctx->dim_decls_tail = NULL;
ctx->const_decls = NULL;
hres = compile_statement(ctx, NULL, stat);
ctx->func = NULL;
}
}
+ if(func->array_cnt) {
+ unsigned array_id = 0;
+ dim_decl_t *dim_decl;
+
+ func->array_descs = compiler_alloc(ctx->code, func->array_cnt * sizeof(array_desc_t));
+ if(!func->array_descs)
+ return E_OUTOFMEMORY;
+
+ for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) {
+ if(dim_decl->is_array) {
+ hres = fill_array_desc(ctx, dim_decl, func->array_descs + array_id++);
+ if(FAILED(hres))
+ return hres;
+ }
+ }
+
+ assert(array_id == func->array_cnt);
+ }
+
return S_OK;
}
func->vars = NULL;
func->var_cnt = 0;
+ func->array_cnt = 0;
func->code_ctx = ctx->code;
func->type = decl->type;
func->is_public = decl->is_public;
static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl)
{
function_decl_t *func_decl, *func_prop_decl;
- class_prop_decl_t *prop_decl;
class_desc_t *class_desc;
+ dim_decl_t *prop_decl;
unsigned i;
HRESULT hres;
return E_OUTOFMEMORY;
class_desc->props[i].is_public = prop_decl->is_public;
+ class_desc->props[i].is_array = prop_decl->is_array;
+
+ if(prop_decl->is_array)
+ class_desc->array_cnt++;
+ }
+
+ if(class_desc->array_cnt) {
+ class_desc->array_descs = compiler_alloc(ctx->code, class_desc->array_cnt*sizeof(*class_desc->array_descs));
+ if(!class_desc->array_descs)
+ return E_OUTOFMEMORY;
+
+ for(prop_decl = class_decl->props, i=0; prop_decl; prop_decl = prop_decl->next) {
+ if(prop_decl->is_array) {
+ hres = fill_array_desc(ctx, prop_decl, class_desc->array_descs + i++);
+ if(FAILED(hres))
+ return hres;
+ }
+ }
}
class_desc->next = ctx->classes;
for(i=0; i < code->bstr_cnt; i++)
SysFreeString(code->bstr_pool[i]);
+ if(code->context)
+ IDispatch_Release(code->context);
heap_pool_free(&code->heap);
heap_free(code->bstr_pool);
{
vbscode_t *ret;
- ret = heap_alloc(sizeof(*ret));
+ ret = heap_alloc_zero(sizeof(*ret));
if(!ret)
return NULL;
ret->option_explicit = ctx->parser.option_explicit;
- ret->bstr_pool = NULL;
- ret->bstr_pool_size = 0;
- ret->bstr_cnt = 0;
- ret->pending_exec = FALSE;
-
ret->main_code.type = FUNC_GLOBAL;
- ret->main_code.name = NULL;
ret->main_code.code_ctx = ret;
- ret->main_code.vars = NULL;
- ret->main_code.var_cnt = 0;
- ret->main_code.arg_cnt = 0;
- ret->main_code.args = NULL;
list_init(&ret->entry);
return ret;
ctx.funcs = NULL;
ctx.func_decls = NULL;
ctx.global_vars = NULL;
- ctx.dim_decls = NULL;
ctx.classes = NULL;
ctx.labels = NULL;
ctx.global_consts = NULL;