// Check that embed fields are not recursive. static bool embed_fields(ast_t* entity, pass_opt_t* opt) { assert(entity != NULL); int state = ast_checkflag(entity, AST_FLAG_RECURSE_2 | AST_FLAG_DONE_2 | AST_FLAG_ERROR_2); // Check for recursive embeds switch(state) { case 0: ast_setflag(entity, AST_FLAG_RECURSE_2); break; case AST_FLAG_RECURSE_2: ast_error(opt->check.errors, entity, "embedded fields can't be recursive"); ast_clearflag(entity, AST_FLAG_RECURSE_2); ast_setflag(entity, AST_FLAG_ERROR_2); return false; case AST_FLAG_DONE_2: return true; case AST_FLAG_ERROR_2: return false; default: assert(0); return false; } AST_GET_CHILDREN(entity, id, typeparams, cap, provides, members); ast_t* member = ast_child(members); while(member != NULL) { if(ast_id(member) == TK_EMBED) { AST_GET_CHILDREN(member, f_id, f_type); ast_t* def = (ast_t*)ast_data(f_type); assert(def != NULL); if(!embed_fields(def, opt)) return false; } member = ast_sibling(member); } ast_clearflag(entity, AST_FLAG_RECURSE_2); ast_setflag(entity, AST_FLAG_DONE_2); return true; }
ast_result_t pass_traits(ast_t** astp, pass_opt_t* options) { ast_t* ast = *astp; switch(ast_id(ast)) { case TK_STRUCT: case TK_CLASS: case TK_ACTOR: if(!trait_entity(ast, options)) return AST_ERROR; if(!embed_fields(ast, options)) return AST_ERROR; break; case TK_PRIMITIVE: if(!trait_entity(ast, options)) return AST_ERROR; if(!add_comparable(ast, options)) return AST_FATAL; break; case TK_INTERFACE: case TK_TRAIT: if(!trait_entity(ast, options)) return AST_ERROR; break; case TK_LET: case TK_VAR: local_types(ast); break; default: break; } return AST_OK; }