diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c index c2179d36833..e54c16a75a5 100644 --- a/dlls/jscript/compile.c +++ b/dlls/jscript/compile.c @@ -1131,6 +1131,108 @@ static HRESULT compile_with_statement(compiler_ctx_t *ctx, with_statement_t *sta return S_OK; } +/* ECMA-262 3rd Edition 12.13 */ +static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t *stat) +{ + unsigned case_cnt = 0, *case_jmps, i, default_jmp; + BOOL have_default = FALSE; + statement_t *stat_iter; + case_clausule_t *iter; + unsigned off_backup; + BOOL prev_no_fallback; + HRESULT hres; + + off_backup = ctx->code_off; + + hres = compile_expression(ctx, stat->expr); + if(FAILED(hres)) + return hres; + + for(iter = stat->case_list; iter; iter = iter->next) { + if(iter->expr) + case_cnt++; + } + + case_jmps = heap_alloc(case_cnt * sizeof(*case_jmps)); + if(!case_jmps) + return E_OUTOFMEMORY; + + i = 0; + for(iter = stat->case_list; iter; iter = iter->next) { + if(!iter->expr) { + have_default = TRUE; + continue; + } + + hres = compile_expression(ctx, iter->expr); + if(FAILED(hres)) + break; + + case_jmps[i] = push_instr(ctx, OP_case); + if(case_jmps[i] == -1) { + hres = E_OUTOFMEMORY; + break; + } + i++; + } + + if(SUCCEEDED(hres)) { + if(push_instr(ctx, OP_pop) != -1) { + default_jmp = push_instr(ctx, OP_jmp); + if(default_jmp == -1) + hres = E_OUTOFMEMORY; + }else { + hres = E_OUTOFMEMORY; + } + } + + if(FAILED(hres)) { + heap_free(case_jmps); + return hres; + } + + i = 0; + for(iter = stat->case_list; iter; iter = iter->next) { + while(iter->next && iter->next->stat == iter->stat) { + instr_ptr(ctx, iter->expr ? case_jmps[i++] : default_jmp)->arg1.uint = ctx->code_off; + iter = iter->next; + } + + instr_ptr(ctx, iter->expr ? case_jmps[i++] : default_jmp)->arg1.uint = ctx->code_off; + + for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter); stat_iter = stat_iter->next) { + prev_no_fallback = ctx->no_fallback; + ctx->no_fallback = TRUE; + hres = compile_statement(ctx, stat_iter); + ctx->no_fallback = prev_no_fallback; + if(hres == E_NOTIMPL) { + ctx->code_off = off_backup; + stat->stat.eval = switch_statement_eval; + return compile_interp_fallback(ctx, &stat->stat); + } + if(FAILED(hres)) + break; + + if(stat_iter->next && push_instr(ctx, OP_pop) == -1) { + hres = E_OUTOFMEMORY; + break; + } + } + if(FAILED(hres)) + break; + } + + heap_free(case_jmps); + if(FAILED(hres)) + return hres; + assert(i == case_cnt); + + if(!have_default) + instr_ptr(ctx, default_jmp)->arg1.uint = ctx->code_off; + + return S_OK; +} + static HRESULT compile_statement(compiler_ctx_t *ctx, statement_t *stat) { switch(stat->type) { @@ -1144,6 +1246,8 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_t *stat) return compile_for_statement(ctx, (for_statement_t*)stat); case STAT_IF: return compile_if_statement(ctx, (if_statement_t*)stat); + case STAT_SWITCH: + return compile_switch_statement(ctx, (switch_statement_t*)stat); case STAT_VAR: return compile_var_statement(ctx, (var_statement_t*)stat); case STAT_WHILE: diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index af15a944114..99c492f829a 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -1073,6 +1073,31 @@ HRESULT labelled_statement_eval(script_ctx_t *ctx, statement_t *stat, return_typ return E_NOTIMPL; } +/* ECMA-262 3rd Edition 12.13 */ +static HRESULT interp_case(exec_ctx_t *ctx) +{ + const unsigned arg = ctx->parser->code->instrs[ctx->ip].arg1.uint; + VARIANT *v; + BOOL b; + HRESULT hres; + + TRACE("\n"); + + v = stack_pop(ctx); + hres = equal2_values(stack_top(ctx), v, &b); + VariantClear(v); + if(FAILED(hres)) + return hres; + + if(b) { + stack_popn(ctx, 1); + ctx->ip = arg; + }else { + ctx->ip++; + } + return S_OK; +} + /* ECMA-262 3rd Edition 12.13 */ HRESULT switch_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret) { diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h index 1ca66302799..263548e1d9d 100644 --- a/dlls/jscript/engine.h +++ b/dlls/jscript/engine.h @@ -52,6 +52,7 @@ typedef struct _func_stack { X(call, 1, ARG_UINT, ARG_UINT) \ X(call_member,1, ARG_UINT, ARG_UINT) \ X(carray, 1, ARG_UINT, 0) \ + X(case, 0, ARG_ADDR, 0) \ X(cnd_nz, 0, ARG_ADDR, 0) \ X(cnd_z, 0, ARG_ADDR, 0) \ X(delete, 1, 0,0) \ diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y index 578ae236ab6..aaec6494f25 100644 --- a/dlls/jscript/parser.y +++ b/dlls/jscript/parser.y @@ -846,7 +846,7 @@ static const statement_eval_t stat_eval_table[] = { compiled_statement_eval, labelled_statement_eval, return_statement_eval, - switch_statement_eval, + compiled_statement_eval, throw_statement_eval, try_statement_eval, compiled_statement_eval,