static void test_bool_ops() { Expr *e_not_t = expr_not(expr_true()); Expr *e_not_f = expr_not(expr_false()); Expr *e_and_tt = expr_and(expr_true(), expr_true()); Expr *e_and_tf = expr_and(expr_true(), expr_false()); Expr *e_or_tf = expr_or(expr_true(), expr_false()); Expr *e_or_ff = expr_or(expr_false(), expr_false()); if (expr_bool_val(e_not_t, NULL, NULL) != 0) fail(); if (expr_bool_val(e_not_f, NULL, NULL) == 0) fail(); if (expr_bool_val(e_and_tt, NULL, NULL) == 0) fail(); if (expr_bool_val(e_and_tf, NULL, NULL) != 0) fail(); if (expr_bool_val(e_or_tf, NULL, NULL) == 0) fail(); if (expr_bool_val(e_or_ff, NULL, NULL) != 0) fail(); expr_free(e_not_t); expr_free(e_not_f); expr_free(e_and_tt); expr_free(e_and_tf); expr_free(e_or_tf); expr_free(e_or_ff); }
Expr* expr_square(Expr* d) { auto r = expr_mul(expr_lit(0.5), d); auto g = expr_and(expr_and(expr_sub(expr_neg(r),expr_x()), expr_sub(expr_x(),r)), expr_and(expr_sub(expr_neg(r),expr_y()), expr_sub(expr_y(),r))); g->xmin = expr_neg(r); g->xmax = r; g->ymin = expr_neg(r); g->ymax = r; return g; }
Expr* expr_rect2(Expr* xd, Expr* yd) { auto xrad = expr_mul(expr_lit(0.5), xd); auto yrad = expr_mul(expr_lit(0.5), yd); auto g = expr_and(expr_and(expr_sub(expr_neg(xrad),expr_x()), expr_sub(expr_x(),xrad)), expr_and(expr_sub(expr_neg(yrad),expr_y()), expr_sub(expr_y(),yrad))); g->xmin = expr_neg(xrad); g->xmax = xrad; g->ymin = expr_neg(yrad); g->ymax = yrad; return g; }
static int expr_or(State_t* state, Node_t *np) { register int tok = expr_and(state, np); while (tok=='|') { Node_t rp; tok = expr_and(state, &rp); if ((numeric(np) && np->num==0) || *np->str==0) *np = rp; } return tok; }
Expr* expr_extrude(Expr* d, Expr* g) { auto r = expr_mul(expr_lit(0.5), d); auto lo = expr_neg(r); auto hi = r; auto tg = expr_and(expr_and(expr_sub(lo,expr_z()), expr_sub(expr_z(),r)), g); tg->xmin = g->xmin; tg->xmax = g->xmax; tg->ymin = g->ymin; tg->ymax = g->ymax; tg->zmin = lo; tg->zmax = hi; // printf("CHECKING EXT TG %p INF XMIN %p YMIN %p ZMIN %p XMAX %p YMAX %p ZMAX %p \n", // tg, tg->xmin, tg->ymin, tg->zmin, tg->xmax, tg->ymax, tg->zmax); return tg; }
/* * Eliminate <->s from an expression. */ static expr_t iffelim_expr(expr_t e, bool c) { if (expr_gettype(e) != EXPRTYPE_OP) return e; exprop_t op = expr_op(e); switch (op) { case EXPROP_NOT: case EXPROP_AND: case EXPROP_OR: { expr_t acc = (op == EXPROP_OR? expr_bool(false): expr_bool(true)); expr_t k, v; for (expritr_t i = expritr(e); expr_getpair(i, &k, &v); expr_next(i)) { bool d = (op != EXPROP_OR); d = (v == expr_bool(true)? !d: d); k = iffelim_expr(k, d); if (v == expr_bool(true)) k = expr_not(k); acc = (op == EXPROP_OR? expr_or(acc, k): expr_and(acc, k)); } return acc; } case EXPROP_IFF: { expr_t x = iffelim_expr(expr_arg(e, 0), c); expr_t y = iffelim_expr(expr_arg(e, 1), c); if (c) { expr_t c1 = expr_or(expr_not(x), y); expr_t c2 = expr_or(x, expr_not(y)); return expr_and(c1, c2); } else { expr_t c1 = expr_and(x, y); expr_t c2 = expr_and(expr_not(x), expr_not(y)); return expr_or(c1, c2); } } default: return e; } }
/* * Context the context into a conjunction of IFFs. */ static expr_t context_to_iffs(context_t context) { iffinfo_t iffinfo = context->iffinfo; expr_t k, v; expr_t and = expr_bool(true); for (iffinfoitr_t i = iffinfoitr(iffinfo); iffinfo_get(i, &k, &v); iffinfo_next(i)) and = expr_and(expr_iff(v, k), and); return and; }
/* * CNF transformation. Assumes `e' is in NNF. */ extern void pass_cnf_expr(const char *filename, size_t lineno, expr_t e, expr_t *b, expr_t *d) { if (expr_gettype(e) != EXPRTYPE_OP) { *b = e; *d = expr_bool(true); return; } struct context_s context0; context_t context = &context0; context->iffinfo = iffinfo_init(); context->clauses = expr_bool(true); context->varid = 0; exprop_t op = expr_op(e); switch (op) { case EXPROP_NOT: case EXPROP_AND: { expr_t and = expr_bool(true), k, v; for (expritr_t i = expritr(e); expr_getpair(i, &k, &v); expr_next(i)) { k = cnf_expr_nextlevel(k, context); if (v == expr_bool(true)) k = expr_not(k); and = expr_and(k, and); } e = and; break; } default: e = cnf_expr_nextlevel(e, context); break; } *b = expr_and(e, context->clauses); *d = context_to_iffs(context); return; }
/* M -> M '*' L | M '&' L | M '&&' L | M L | L */ static inline node* expr_and(expr *e) { node *a; node *b; expr_eat_white(e); a = expr_sym(e); expr_eat_white(e); if (e->str[0]=='&' && e->str[1]=='&') { e->str += 2; b = expr_and(e); return newnode(AND,0,a,b); } else if (e->str[0]=='&' || e->str[0]=='*') { e->str ++; b = expr_and(e); return newnode(AND,0,a,b); } else if ((e->str[0]>='A' && e->str[0]<='Z') || (e->str[0]>='a' && e->str[0]<='z') || e->str[0]=='(' || e->str[0]=='[') { b = expr_and(e); return newnode(AND,0,a,b); } else { return a; } }
/* * Flattening pass. */ extern expr_t pass_flatten_expr(const char *filename, size_t lineno, expr_t e) { struct context_s context0; context_t context = &context0; context->cseinfo = cseinfo_init(); context->varid = 0; context->file = filename; context->line = lineno; context->error = false; e = flatten(e, true, context); e = expr_and(e, context_to_expr(context)); if (context->error) return (expr_t)NULL; else return e; }
/* S -> S '+' M | S '|' M | S '||' M | M */ static inline node* expr_or(expr *e) { node *a; node *b; expr_eat_white(e); a = expr_and(e); expr_eat_white(e); if (e->str[0]=='|' && e->str[1]=='|') { e->str += 2; b = expr_or(e); return newnode(OR,0,a,b); } else if (e->str[0]=='|' || e->str[0]=='+') { e->str ++; b = expr_or(e); return newnode(OR,0,a,b); } else { return a; } }
/* * Convert the cxt back into an expression. */ static expr_t context_to_expr(context_t cxt) { expr_t k; expr_t v; expr_t and = expr_bool(true); cseinfo_t cseinfo = cxt->cseinfo; for (cseinfoitr_t i = cseinfoitr(cseinfo); cseinfo_get(i, &k, &v); cseinfo_next(i)) { typeinst_t type = expr_gettypeinst(k); term_t arg; if (type == TYPEINST_BOOL) arg = expr_iff(v, k); else arg = flatten_eq_to_builtin((exprop_t)NULL, v, k, true, cxt); and = expr_and(arg, and); } return and; }
static void test_select() { int a, b, c; Type ta, tb, tc; Rel *src = load("select_1"); head_attr(src->head, "b", &b, &tb); Expr *expr = expr_eq(expr_real(1.01), expr_attr(b, tb)); Rel *r = rel_select(src, expr); if (!equal(r, "select_1_res")) fail(); src = load("select_2"); head_attr(src->head, "a", &a, &ta); head_attr(src->head, "b", &b, &tb); head_attr(src->head, "c", &c, &tc); expr = expr_or(expr_gt(expr_attr(b, tb), expr_real(4.00)), expr_lt(expr_attr(a, ta), expr_int(2))); expr = expr_or(expr, expr_lt(expr_attr(c, tc), expr_str("aab"))); r = rel_select(src, expr); if (!equal(r, "select_2_res")) fail(); src = load("select_3"); head_attr(src->head, "a", &a, &ta); head_attr(src->head, "b", &b, &tb); expr = expr_and(expr_not(expr_attr(a, ta)), expr_not(expr_eq(expr_attr(b, tb), expr_real(1.01)))); r = rel_select(src, expr); if (!equal(r, "select_3_res")) fail(); }
/* * Flattening transformation. */ static expr_t flatten(expr_t e, bool toplevel, context_t cxt) { if (expr_gettype(e) != EXPRTYPE_OP) return e; exprop_t op = expr_op(e); switch (op) { case EXPROP_EQ: { expr_t x, y; if (expr_view_x_eq_func(e, &x, &y)) { y = flatten(y, false, cxt); return flatten_eq_to_builtin(exprop_atom_make(ATOM_INT_EQ), x, y, toplevel, cxt); } // Fall-through: } case EXPROP_NEQ: case EXPROP_LT: case EXPROP_LEQ: case EXPROP_GT: case EXPROP_GEQ: { // Check if already a flattened comparison: exprop_t binop, cmp; expr_t x, y, z; if (expr_view_x_cmp_y(e, &x, &cmp, &y)) return flatten_x_cmp_y_to_builtin(x, cmp, y, cxt); if (expr_view_x_cmp_y_op_z(e, &x, &cmp, &y, &binop, &z)) { y = expr_make(binop, y, z); return flatten_eq_to_builtin(exprop_atom_make(ATOM_INT_EQ), x, y, toplevel, cxt); } e = expr_arg(e, 1); if (!expr_view_plus_sign_partition(e, &x, &y)) panic("failed to partition (+) expression"); if (op == EXPROP_EQ) { expr_t x0, x1; if (expr_view_plus_first_partition(x, &x0, &x1)) { x1 = flatten_to_primitive(x1, cxt); y = flatten_to_var(y, cxt); e = expr_make(EXPROP_ADD, x0, x1); return flatten_eq_to_builtin(exprop_atom_make(ATOM_INT_EQ), y, e, toplevel, cxt); } expr_t y0, y1; if (expr_view_plus_first_partition(y, &y0, &y1)) { y1 = flatten_to_primitive(y1, cxt); x = flatten_to_var(x, cxt); e = expr_make(EXPROP_ADD, y0, y1); return flatten_eq_to_builtin(exprop_atom_make(ATOM_INT_EQ), x, e, toplevel, cxt); } x = flatten_to_primitive(x, cxt); y = flatten_to_primitive(y, cxt); return flatten_eq_to_builtin(exprop_atom_make(ATOM_INT_EQ), x, y, toplevel, cxt); } else { x = flatten_to_primitive(x, cxt); y = flatten_to_primitive(y, cxt); if (expr_gettype(y) == EXPRTYPE_NUM) { num_t c = expr_getnum(y); y = expr_num(c - 1); e = flatten_x_cmp_y_to_builtin(x, cmp, y, cxt); return expr_not(e); } else return flatten_x_cmp_y_to_builtin(y, cmp, x, cxt); } } case EXPROP_NOT: { expr_t arg = expr_arg(e, 0); arg = flatten(arg, toplevel, cxt); return expr_not(arg); } case EXPROP_IFF: { expr_t arg0 = flatten(expr_arg(e, 0), false, cxt); expr_t arg1 = flatten(expr_arg(e, 1), false, cxt); return expr_iff(arg0, arg1); } case EXPROP_AND: { expr_t and = expr_bool(true), k, v; for (expritr_t i = expritr(e); expr_getpair(i, &k, &v); expr_next(i)) { k = flatten(k, toplevel, cxt); if (v == expr_bool(true)) k = expr_not(k); and = expr_and(k, and); } return and; } case EXPROP_OR: { expr_t or = expr_bool(false), k, v; for (expritr_t i = expritr(e); expr_getpair(i, &k, &v); expr_next(i)) { k = flatten(k, false, cxt); if (v == expr_bool(true)) k = expr_not(k); or = expr_or(k, or); } return or; } case EXPROP_ADD: case EXPROP_MUL: { size_t a = expr_arity(e); expr_t args[a]; expr_args(e, args); for (size_t i = 0; i < a; i++) args[i] = flatten_to_primitive(args[i], cxt); e = expr(op, args); return e; } case EXPROP_POW: { expr_t arg1 = expr_arg(e, 1); if (expr_gettype(arg1) != EXPRTYPE_NUM) { flatten_bad_pow: error("(%s: %zu) failed to flatten expression `!y%s!d'; " "exponent must be a positive constant, found `!y%s!d'", cxt->file, cxt->line, show(expr_term(e)), show(expr_term(arg1))); cxt->error = true; return e; } num_t c = expr_getnum(arg1); if (c <= 1) goto flatten_bad_pow; expr_t arg0 = flatten_to_primitive(expr_arg(e, 0), cxt); expr_t e = expr_pow(arg0, arg1); return e; } default: { atom_t atom = expr_sym(e); if (atom == ATOM_NIL_EQ || atom == ATOM_STR_EQ || atom == ATOM_ATOM_EQ || is_eq(atom)) { expr_t x = expr_arg(e, 0), y = expr_arg(e, 1); x = flatten(x, false, cxt); y = flatten(y, false, cxt); return flatten_eq_to_builtin(expr_op(e), x, y, toplevel, cxt); } size_t a = expr_arity(e); expr_t args[a]; expr_args(e, args); typesig_t sig = typeinst_get_decl((atom_t)op); for (size_t i = 0; i < a; i++) { typeinst_t t = typeinst_decl_arg(sig, i); if (t != typeinst_make_ground(t)) args[i] = flatten_to_var(args[i], cxt); else { // Note: type check does not check instances; we check // here. if (type(args[i]) == VAR || type(args[i]) == FUNC) { error("(%s: %zu) failed to flatten expression " "`!y%s!d'; cannot flatten %s argument " "`!y%s!d' to a ground term", cxt->file, cxt->line, show(expr_term(e)), (type(args[i]) == VAR? "variable": "function call"), show(expr_term(args[i]))); cxt->error = true; } } } e = expr(op, args); return e; } } }
Expr* expr_rem(Expr* a, Expr* b) { return expr_and(a, expr_neg(b)); }
/* * Insert a new clause. */ static void context_insertclause(context_t context, expr_t clause) { context->clauses = expr_and(context->clauses, clause); }