static void set_fields_undefined(ast_t* ast) { assert(ast_id(ast) == TK_NEW); ast_t* members = ast_parent(ast); ast_t* member = ast_child(members); while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: case TK_EMBED: { AST_GET_CHILDREN(member, id, type, expr); // If this field has an initialiser, we accept SYM_DEFINED for it. if(ast_id(expr) != TK_NONE) break; // Mark this field as SYM_UNDEFINED. ast_setstatus(ast, ast_name(id), SYM_UNDEFINED); break; } default: {} } member = ast_sibling(member); } }
bool expr_consume(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, cap, term); ast_t* type = ast_type(term); if(is_typecheck_error(type)) return false; const char* name = NULL; switch(ast_id(term)) { case TK_VARREF: case TK_LETREF: case TK_PARAMREF: { ast_t* id = ast_child(term); name = ast_name(id); break; } case TK_THIS: { name = stringtab("this"); break; } default: ast_error(opt->check.errors, ast, "consume must take 'this', a local, or a parameter"); return false; } // Can't consume from an outer scope while in a loop condition. if((opt->check.frame->loop_cond != NULL) && !ast_within_scope(opt->check.frame->loop_cond, ast, name)) { ast_error(opt->check.errors, ast, "can't consume from an outer scope in a loop condition"); return false; } ast_setstatus(ast, name, SYM_CONSUMED); token_id tcap = ast_id(cap); ast_t* c_type = consume_type(type, tcap); if(c_type == NULL) { ast_error(opt->check.errors, ast, "can't consume to this capability"); ast_error_continue(opt->check.errors, term, "expression type is %s", ast_print_type(type)); return false; } ast_settype(ast, c_type); return true; }
static bool assign_id(typecheck_t* t, ast_t* ast, bool let, bool need_value) { assert(ast_id(ast) == TK_ID); const char* name = ast_name(ast); sym_status_t status; ast_get(ast, name, &status); switch(status) { case SYM_UNDEFINED: if(need_value) { ast_error(ast, "the left side is undefined but its value is used"); return false; } ast_setstatus(ast, name, SYM_DEFINED); return true; case SYM_DEFINED: if(let) { ast_error(ast, "can't assign to a let or embed definition more than once"); return false; } return true; case SYM_CONSUMED: { bool ok = true; if(need_value) { ast_error(ast, "the left side is consumed but its value is used"); ok = false; } if(let) { ast_error(ast, "can't assign to a let or embed definition more than once"); ok = false; } if(t->frame->try_expr != NULL) { ast_error(ast, "can't reassign to a consumed identifier in a try expression"); ok = false; } if(ok) ast_setstatus(ast, name, SYM_DEFINED); return ok; } default: {} } assert(0); return false; }