static HRESULT compile_literal(compiler_ctx_t *ctx, literal_t *literal) { switch(literal->type) { case LT_BOOL: return push_instr_int(ctx, OP_bool, literal->u.bval); case LT_DOUBLE: return push_instr_double(ctx, OP_double, literal->u.dval); case LT_INT: return push_instr_int(ctx, OP_int, literal->u.lval); case LT_NULL: return push_instr(ctx, OP_null) ? S_OK : E_OUTOFMEMORY; case LT_STRING: return push_instr_str(ctx, OP_str, literal->u.wstr); case LT_REGEXP: { unsigned instr; WCHAR *str; str = compiler_alloc(ctx->code, (literal->u.regexp.str_len+1)*sizeof(WCHAR)); if(!str) return E_OUTOFMEMORY; memcpy(str, literal->u.regexp.str, literal->u.regexp.str_len*sizeof(WCHAR)); str[literal->u.regexp.str_len] = 0; instr = push_instr(ctx, OP_regexp); if(!instr) return E_OUTOFMEMORY; instr_ptr(ctx, instr)->arg1.str = str; instr_ptr(ctx, instr)->arg2.lng = literal->u.regexp.flags; return S_OK; } default: assert(0); } }
static HRESULT compile_increment_expression(compiler_ctx_t *ctx, unary_expression_t *expr, jsop_t op, int n) { HRESULT hres; if(!is_memberid_expr(expr->expression->type)) { hres = compile_expression(ctx, expr->expression); if(FAILED(hres)) return hres; return push_instr_uint(ctx, OP_throw_ref, JS_E_ILLEGAL_ASSIGN); } hres = compile_memberid_expression(ctx, expr->expression, fdexNameEnsure); if(FAILED(hres)) return hres; return push_instr_int(ctx, op, n); }
static HRESULT compile_new_expression(compiler_ctx_t *ctx, call_expression_t *expr) { unsigned arg_cnt = 0; argument_t *arg; HRESULT hres; hres = compile_expression(ctx, expr->expression); if(FAILED(hres)) return hres; for(arg = expr->argument_list; arg; arg = arg->next) { hres = compile_expression(ctx, arg->expr); if(FAILED(hres)) return hres; arg_cnt++; } return push_instr_int(ctx, OP_new, arg_cnt); }
static HRESULT compile_onerror_statement(compile_ctx_t *ctx, onerror_statement_t *stat) { return push_instr_int(ctx, OP_errmode, stat->resume_next); }
static HRESULT compile_expression(compile_ctx_t *ctx, expression_t *expr) { switch(expr->type) { case EXPR_ADD: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_add); case EXPR_AND: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_and); case EXPR_BOOL: return push_instr_int(ctx, OP_bool, ((bool_expression_t*)expr)->value); case EXPR_CONCAT: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_concat); case EXPR_DIV: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_div); case EXPR_DOUBLE: return push_instr_double(ctx, OP_double, ((double_expression_t*)expr)->value); case EXPR_EMPTY: return push_instr(ctx, OP_empty) != -1 ? S_OK : E_OUTOFMEMORY; case EXPR_EQUAL: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_equal); case EXPR_EQV: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_eqv); case EXPR_EXP: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_exp); case EXPR_GT: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_gt); case EXPR_GTEQ: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_gteq); case EXPR_IDIV: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_idiv); case EXPR_IS: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_is); case EXPR_IMP: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_imp); case EXPR_LT: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_lt); case EXPR_LTEQ: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_lteq); case EXPR_ME: return push_instr(ctx, OP_me) != -1 ? S_OK : E_OUTOFMEMORY; case EXPR_MEMBER: return compile_member_expression(ctx, (member_expression_t*)expr, TRUE); case EXPR_MOD: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_mod); case EXPR_MUL: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_mul); case EXPR_NEG: return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_neg); case EXPR_NEQUAL: 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_NOT: return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_not); case EXPR_NOTHING: return push_instr(ctx, OP_nothing) != -1 ? S_OK : E_OUTOFMEMORY; case EXPR_NULL: return push_instr(ctx, OP_null) != -1 ? S_OK : E_OUTOFMEMORY; case EXPR_OR: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_or); case EXPR_STRING: return push_instr_str(ctx, OP_string, ((string_expression_t*)expr)->value); case EXPR_SUB: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_sub); case EXPR_USHORT: return push_instr_int(ctx, OP_short, ((int_expression_t*)expr)->value); case EXPR_ULONG: return push_instr_int(ctx, OP_long, ((int_expression_t*)expr)->value); case EXPR_XOR: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_xor); default: FIXME("Unimplemented expression type %d\n", expr->type); return E_NOTIMPL; } return S_OK; }
static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *stat) { statement_ctx_t loop_ctx = {2}; 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) return E_OUTOFMEMORY; instr_ptr(ctx, instr)->arg1.bstr = identifier; instr_ptr(ctx, instr)->arg2.uint = 0; hres = compile_expression(ctx, stat->to_expr); if(FAILED(hres)) return hres; if(!push_instr(ctx, OP_val)) 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)) return E_OUTOFMEMORY; }else { hres = push_instr_int(ctx, OP_short, 1); if(FAILED(hres)) return hres; } loop_ctx.for_end_label = alloc_label(ctx); if(!loop_ctx.for_end_label) return E_OUTOFMEMORY; step_instr = push_instr(ctx, OP_step); if(!step_instr) return E_OUTOFMEMORY; instr_ptr(ctx, step_instr)->arg2.bstr = identifier; instr_ptr(ctx, step_instr)->arg1.uint = loop_ctx.for_end_label; hres = compile_statement(ctx, &loop_ctx, stat->body); if(FAILED(hres)) return hres; instr = push_instr(ctx, OP_incc); if(!instr) return E_OUTOFMEMORY; instr_ptr(ctx, instr)->arg1.bstr = identifier; hres = push_instr_addr(ctx, OP_jmp, step_instr); if(FAILED(hres)) return hres; hres = push_instr_uint(ctx, OP_pop, 2); if(FAILED(hres)) return hres; label_set_addr(ctx, loop_ctx.for_end_label); return S_OK; }
/* ECMA-262 3rd Edition 12.6.4 */ static HRESULT compile_forin_statement(compiler_ctx_t *ctx, forin_statement_t *stat) { statement_ctx_t stat_ctx = {4, FALSE, FALSE}; HRESULT hres; if(stat->variable) { hres = compile_variable_list(ctx, stat->variable); if(FAILED(hres)) return hres; } stat_ctx.break_label = alloc_label(ctx); if(!stat_ctx.break_label) return E_OUTOFMEMORY; stat_ctx.continue_label = alloc_label(ctx); if(!stat_ctx.continue_label) return E_OUTOFMEMORY; hres = compile_expression(ctx, stat->in_expr); if(FAILED(hres)) return hres; if(stat->variable) { hres = push_instr_bstr_uint(ctx, OP_identid, stat->variable->identifier, fdexNameEnsure); if(FAILED(hres)) return hres; }else if(is_memberid_expr(stat->expr->type)) { hres = compile_memberid_expression(ctx, stat->expr, fdexNameEnsure); if(FAILED(hres)) return hres; }else { hres = push_instr_uint(ctx, OP_throw_ref, JS_E_ILLEGAL_ASSIGN); if(FAILED(hres)) return hres; /* FIXME: compile statement anyways when we depend on compiler to check errors */ return S_OK; } hres = push_instr_int(ctx, OP_int, DISPID_STARTENUM); if(FAILED(hres)) return hres; /* FIXME: avoid */ if(!push_instr(ctx, OP_undefined)) return E_OUTOFMEMORY; label_set_addr(ctx, stat_ctx.continue_label); hres = push_instr_uint(ctx, OP_forin, stat_ctx.break_label); if(FAILED(hres)) return E_OUTOFMEMORY; hres = compile_statement(ctx, &stat_ctx, stat->statement); if(FAILED(hres)) return hres; hres = push_instr_uint(ctx, OP_jmp, stat_ctx.continue_label); if(FAILED(hres)) return hres; label_set_addr(ctx, stat_ctx.break_label); return S_OK; }