int tree_fold(struct tree *tree, fold_function *f, int acc) //@ requires [?frac]tree(tree, ?depth) &*& is_fold_function(f) == true; //@ ensures [frac]tree(tree, depth); { if (tree == 0) { return acc; } else { //@ open [frac]tree(tree, depth); acc = tree_fold(tree->left, f, acc); acc = tree_fold(tree->right, f, acc); acc = f(acc, tree->value); return acc; //@ close [frac]tree(tree, depth); } }
void folder(struct fold_data *data) //@ : thread_run_joinable //@ requires thread_run_pre(folder)(data, ?info); //@ ensures thread_run_post(folder)(data, info); { //@ open thread_run_pre(folder)(data, info); int acc = tree_fold(data->tree, data->f, data->acc); data->acc = acc; //@ close thread_run_post(folder)(data, info); }
int tree_fold(tree_t node, c_value_t *pval) { semainfo_t si; struct sema_def *def; c_value_t v1, v2; int opcode; size_t size; typeinfo_t tt; tree_t decl; if (!node) goto failure; switch (node->kind) { case NODE_EXPRTERNARY: if (tree_fold(node->node.refs[3], &v1) < 0) goto failure; if (c_value_is_true(&v1)) { if (tree_fold(node->node.refs[5], pval) < 0) goto failure; } else { if (tree_fold(node->node.refs[7], pval) < 0) goto failure; } break; case NODE_EXPRBINARY: opcode = sema_binop_to_c_operation(node->node.refs[4]->kind); switch (opcode) { case COP_ASSIGN: case COP_MULASSIGN: case COP_DIVASSIGN: case COP_MODASSIGN: case COP_ADDASSIGN: case COP_SUBASSIGN: case COP_ASLASSIGN: case COP_ASRASSIGN: case COP_ANDASSIGN: case COP_XORASSIGN: case COP_ORASSIGN: goto failure; case COP_COMMA: if (tree_fold(node->node.refs[3], &v1) < 0) goto failure; if (tree_fold(node->node.refs[5], pval) < 0) goto failure; break; case COP_LOGAND: if (tree_fold(node->node.refs[3], &v1) < 0) goto failure; if (c_value_is_false(&v1)) goto set_false_value; if (tree_fold(node->node.refs[5], &v2) < 0) goto failure; if (c_value_is_false(&v2)) goto set_false_value; goto set_true_value; case COP_LOGOR: if (tree_fold(node->node.refs[3], &v1) < 0) goto failure; if (c_value_is_true(&v1)) goto set_true_value; if (tree_fold(node->node.refs[5], &v2) < 0) goto failure; if (c_value_is_true(&v2)) goto set_true_value; goto set_false_value; case COP_BITOR: case COP_BITXOR: case COP_BITAND: case COP_EQ: case COP_NE: case COP_LT: case COP_GT: case COP_LE: case COP_GE: case COP_ASR: case COP_ASL: case COP_ADD: case COP_SUB: case COP_MUL: case COP_DIV: case COP_MOD: break; default: SWERR(("tree_fold: unhandled binary opcode: %d", opcode)); } if (tree_fold(node->node.refs[3], &v1) < 0) goto failure; if (tree_fold(node->node.refs[5], &v2) < 0) goto failure; if (c_value_operation(0, opcode, &v1, &v2, 0, pval) < 0) goto failure; break; case NODE_EXPRCAST: if (tree_fold(node->node.refs[6], &v1) < 0) goto failure; tt = sema_get_expr_type(node->node.refs[6]); ASSERT(tt); if (tt->tag != CPT_ARITH && tt->tag != CPT_ENUM) goto failure; tt = sema_get_expr_type(node); if (tt->tag != CPT_ARITH) goto failure; if (c_value_cast(&v1, sema_typeinfo_to_index(tt), pval) < 0) goto failure; break; case NODE_EXPRSIZEOF: decl = node->node.refs[5]; if (!decl) goto failure; ASSERT(decl->kind == NODE_DECL); si = decl->node.sema; if (!si) goto failure; ASSERT(si->tag == ST_TYPE); tt = si->s_type.type; size = sema_get_type_size(tt); if (size == SEMA_NO_SIZE) goto failure; memset(pval, 0, sizeof(*pval)); pval->tag = C_ULONG; pval->v.ct_ulint = size; break; case NODE_EXPRUNARY: opcode = sema_unop_to_c_operation(node->node.refs[3]->kind); switch (opcode) { case COP_PREINC: case COP_PREDEC: goto failure; case COP_SIZEOF: tt = sema_get_expr_type(node->node.refs[4]); size = sema_get_type_size(tt); if (size == SEMA_NO_SIZE) goto failure; memset(pval, 0, sizeof(*pval)); pval->tag = C_ULONG; pval->v.ct_ulint = size; break; case COP_DEREF: case COP_ADDRESS: goto failure; case COP_PLUS: case COP_MINUS: case COP_BITNOT: case COP_LOGNOT: if (tree_fold(node->node.refs[4], &v1) < 0) goto failure; if (c_value_operation(0, opcode, &v1, 0, 0, pval) < 0) goto failure; break; default: SWERR(("tree_fold: unhandled unary opcode: %d", opcode)); } break; case NODE_EXPRARRAY: case NODE_EXPRCALL: case NODE_EXPRFIELD: case NODE_EXPRPOSTFIX: return -1; case NODE_EXPRBRACKETS: return tree_fold(node->node.refs[4], pval); case NODE_EXPRIDENT: si = node->node.sema; if (!si) goto failure; ASSERT(si->tag == ST_IDUSE); def = si->s_iduse.def; ASSERT(def->type); if (def->type->tag != CPT_ENUM) goto failure; if (!SSC_IS_ENUMCONST(def->flags)) goto failure; memset(pval, 0, sizeof(*pval)); memcpy(pval, def->value, sizeof(c_value_t)); break; case NODE_EXPRCONST: memset(pval, 0, sizeof(*pval)); memcpy(pval, &node->node.refs[3]->val.val, sizeof(c_value_t)); break; case NODE_EXPRSTRING: case NODE_EXPRVASTART: case NODE_EXPRVAARG: case NODE_EXPRVAEND: case NODE_EXPRINIT: case NODE_EXPRASM: return -1; default: SWERR(("tree_fold: bad node: kind == %d", node->kind)); } return 0; failure: memset(pval, 0, sizeof(*pval)); pval->tag = C_INT; return -1; set_false_value: memset(pval, 0, sizeof(*pval)); pval->tag = C_INT; return 0; set_true_value: memset(pval, 0, sizeof(*pval)); pval->tag = C_INT; pval->v.ct_int = 1; return 0; }