bool expr_break(typecheck_t* t, ast_t* ast) { if(t->frame->loop_body == NULL) { ast_error(ast, "must be in a loop"); return false; } if(!ast_all_consumes_in_scope(t->frame->loop_body, ast)) return false; // break is always the last expression in a sequence assert(ast_sibling(ast) == NULL); ast_settype(ast, ast_from(ast, TK_BREAK)); ast_inheritflags(ast); // Add type to loop. ast_t* body = ast_child(ast); if(is_control_type(ast_type(body))) { ast_error(body, "break value cannot be a control statement"); return false; } ast_t* loop_type = ast_type(t->frame->loop); loop_type = control_type_add_branch(loop_type, body); ast_settype(t->frame->loop, loop_type); return true; }
bool expr_repeat(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, body, cond, else_clause); ast_t* body_type = ast_type(body); ast_t* cond_type = ast_type(cond); ast_t* else_type = ast_type(else_clause); if(is_typecheck_error(cond_type)) return false; if(!is_bool(cond_type)) { ast_error(opt->check.errors, cond, "condition must be a Bool"); return false; } if(is_typecheck_error(body_type) || is_typecheck_error(else_type)) return false; // All consumes have to be in scope when the loop body finishes. errorframe_t errorf = NULL; if(!ast_all_consumes_in_scope(body, body, &errorf)) { errorframe_report(&errorf, opt->check.errors); return false; } // Union with any existing type due to a break expression. ast_t* type = ast_type(ast); // No symbol status is inherited from the loop body or condition. Nothing // from outside can be consumed, and definitions inside may not occur. if(!is_control_type(body_type)) type = control_type_add_branch(opt, type, body); if(!is_control_type(else_type)) { type = control_type_add_branch(opt, type, else_clause); ast_inheritbranch(ast, else_clause); // Use a branch count of two instead of one. This means we will pick up any // consumes, but not any definitions, since definitions may not occur. ast_consolidate_branches(ast, 2); } if(type == NULL) type = ast_from(ast, TK_REPEAT); ast_settype(ast, type); literal_unify_control(ast, opt); // Push our symbol status to our parent scope. ast_inheritstatus(ast_parent(ast), ast); return true; }
bool expr_continue(typecheck_t* t, ast_t* ast) { if(t->frame->loop_body == NULL) { ast_error(ast, "must be in a loop"); return false; } if(!ast_all_consumes_in_scope(t->frame->loop_body, ast)) return false; // continue is always the last expression in a sequence assert(ast_sibling(ast) == NULL); ast_settype(ast, ast_from(ast, TK_CONTINUE)); return true; }
bool expr_break(pass_opt_t* opt, ast_t* ast) { typecheck_t* t = &opt->check; if(t->frame->loop_body == NULL) { ast_error(opt->check.errors, ast, "must be in a loop"); return false; } errorframe_t errorf = NULL; if(!ast_all_consumes_in_scope(t->frame->loop_body, ast, &errorf)) { errorframe_report(&errorf, opt->check.errors); return false; } // break is always the last expression in a sequence assert(ast_sibling(ast) == NULL); ast_settype(ast, ast_from(ast, TK_BREAK)); // Add type to loop. ast_t* body = ast_child(ast); if(ast_id(body) != TK_NONE) { if(is_control_type(ast_type(body))) { ast_error(opt->check.errors, body, "break value cannot be a control statement"); return false; } ast_t* loop_type = ast_type(t->frame->loop); // If there is no body the break will jump to the else branch, whose type // has already been added to the loop type. loop_type = control_type_add_branch(opt, loop_type, body); ast_settype(t->frame->loop, loop_type); } return true; }
bool expr_continue(pass_opt_t* opt, ast_t* ast) { typecheck_t* t = &opt->check; if(t->frame->loop_body == NULL) { ast_error(opt->check.errors, ast, "must be in a loop"); return false; } errorframe_t errorf = NULL; if(!ast_all_consumes_in_scope(t->frame->loop_body, ast, &errorf)) { errorframe_report(&errorf, opt->check.errors); return false; } // continue is always the last expression in a sequence assert(ast_sibling(ast) == NULL); ast_settype(ast, ast_from(ast, TK_CONTINUE)); return true; }