static HRESULT compile_member_expression(compile_ctx_t *ctx, member_expression_t *expr, BOOL ret_val) { unsigned arg_cnt = 0; HRESULT hres; if(ret_val && !expr->args) { expression_t *const_expr; const_expr = lookup_const_decls(ctx, expr->identifier, TRUE); if(const_expr) return compile_expression(ctx, const_expr); } hres = compile_args(ctx, expr->args, &arg_cnt); if(FAILED(hres)) return hres; if(expr->obj_expr) { hres = compile_expression(ctx, expr->obj_expr); if(FAILED(hres)) return hres; hres = push_instr_bstr_uint(ctx, ret_val ? OP_mcall : OP_mcallv, expr->identifier, arg_cnt); }else { hres = push_instr_bstr_uint(ctx, ret_val ? OP_icall : OP_icallv, expr->identifier, arg_cnt); } return hres; }
static HRESULT compile_assignment(compile_ctx_t *ctx, member_expression_t *member_expr, expression_t *value_expr, BOOL is_set) { unsigned args_cnt; vbsop_t op; HRESULT hres; if(member_expr->obj_expr) { hres = compile_expression(ctx, member_expr->obj_expr); if(FAILED(hres)) return hres; op = is_set ? OP_set_member : OP_assign_member; }else { op = is_set ? OP_set_ident : OP_assign_ident; } hres = compile_expression(ctx, value_expr); if(FAILED(hres)) return hres; hres = compile_args(ctx, member_expr->args, &args_cnt); if(FAILED(hres)) return hres; return push_instr_bstr_uint(ctx, op, member_expr->identifier, args_cnt); }
static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *expr, unsigned flags) { HRESULT hres = S_OK; switch(expr->type) { case EXPR_IDENT: { identifier_expression_t *ident_expr = (identifier_expression_t*)expr; hres = push_instr_bstr_uint(ctx, OP_identid, ident_expr->identifier, flags); break; } case EXPR_ARRAY: { binary_expression_t *array_expr = (binary_expression_t*)expr; hres = compile_expression(ctx, array_expr->expression1); if(FAILED(hres)) return hres; hres = compile_expression(ctx, array_expr->expression2); if(FAILED(hres)) return hres; hres = push_instr_uint(ctx, OP_memberid, flags); break; } case EXPR_MEMBER: { member_expression_t *member_expr = (member_expression_t*)expr; hres = compile_expression(ctx, member_expr->expression); if(FAILED(hres)) return hres; /* FIXME: Potential optimization */ hres = push_instr_str(ctx, OP_str, member_expr->identifier); if(FAILED(hres)) return hres; hres = push_instr_uint(ctx, OP_memberid, flags); break; } default: assert(0); } return hres; }
/* 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; }