Пример #1
0
static expr *parse_primary(void)
{
	switch(tok_cur){
		case tok_ident: tok_next(); return expr_ident();
		case tok_num:   tok_next(); return expr_num(tok_cur_num);
		case tok_lparen:
		{
			expr *e;
			tok_next();
			e = parse();
			if(tok_cur != tok_rparen)
				CPP_DIE("close paren expected");
			tok_next();
			return e;
		}

		case tok_not:
		case tok_bnot:
		case tok_minus:
		{
			const e_op op = tok_cur;
			tok_next();
			return expr_new_uop(op, parse_primary());
		}

		default:
			break;
	}

	{
		char s[2];
		*s = tok_cur, s[1] = '\0';
		CPP_DIE("expression expected (got %s)", tok_cur == tok_eof ? "eof" : s);
	}
}
Пример #2
0
/*
 * 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;
        }
    }
}
Пример #3
0
/*
 * Flatten an equality expression `x = y'.  Assumes x and y are already
 * flattened.
 */
static expr_t flatten_eq_to_builtin(exprop_t op, expr_t x, expr_t y,
    bool toplevel, context_t cxt)
{
    if (expr_gettype(x) == EXPRTYPE_VAR && expr_gettype(y) == EXPRTYPE_VAR)
        return expr_make(op, x, y);
    if (expr_gettype(y) == EXPRTYPE_VAR)
    {
        expr_t t = x;
        x = y;
        y = t;
    }
    if (expr_gettype(x) != EXPRTYPE_VAR)
        x = context_update(cxt, x);
    if (!toplevel)
        y = context_update(cxt, y);

    // Special-case handling of constants and variables:
    switch (expr_gettype(y))
    {
        case EXPRTYPE_VAR:
            if (expr_compare(x, y) < 0)
                return expr_make(op, x, y);
            else
                return expr_make(op, y, x);
        case EXPRTYPE_NUM:
            return expr_make(exprop_atom_make(ATOM_INT_EQ_C), x, y);
        case EXPRTYPE_NIL:
            return expr_make(exprop_atom_make(ATOM_NIL_EQ_C), x, y);
        case EXPRTYPE_STR:
            return expr_make(exprop_atom_make(ATOM_STR_EQ_C), x, y);
        case EXPRTYPE_ATOM:
            return expr_make(exprop_atom_make(ATOM_ATOM_EQ_C), x, y);
        case EXPRTYPE_OP:
            break;
        default:
            panic("unexpected expr type (%d)", expr_gettype(y));
    }

    // Special-case handling of add/mul:
    exprop_t fop = expr_op(y);
    switch (fop)
    {
        case EXPROP_ADD:
        {
            expr_t a = expr_arg(y, 0);
            expr_t b = expr_arg(y, 1);
            if (expr_gettype(a) == EXPRTYPE_NUM)
            {
                expr_t t = a; a = b; b = t;
            }
            if (expr_gettype(b) == EXPRTYPE_NUM)
            {
                num_t c = expr_getnum(b);
                if (c < 0)
                    return expr_make(exprop_atom_make(ATOM_INT_EQ_PLUS_C),
                        a, x, expr_num(-c));
                else
                    return expr_make(exprop_atom_make(ATOM_INT_EQ_PLUS_C),
                        x, a, b);
            }
            else
                return expr_make(exprop_atom_make(ATOM_INT_EQ_PLUS), x, a, b);
        }
        case EXPROP_MUL:
        {
            expr_t a = expr_arg(y, 0);
            expr_t b = expr_arg(y, 1);
            if (expr_gettype(a) == EXPRTYPE_NUM)
            {
                expr_t t = a; a = b; b = t;
            }
            if (expr_gettype(b) == EXPRTYPE_NUM)
                return expr_make(exprop_atom_make(ATOM_INT_EQ_MUL_C), x, a, b);
            else
                return expr_make(exprop_atom_make(ATOM_INT_EQ_MUL), x, a, b);
        }
        case EXPROP_POW:
        {
            expr_t a = expr_arg(y, 0);
            expr_t b = expr_arg(y, 1);
            return expr_make(exprop_atom_make(ATOM_INT_EQ_POW_C), x, a, b);
        }
        default:
            break;
    }

    // Generic function calls:
    atom_t atom = expr_sym(y);
    const char *name = atom_name(atom);
    size_t arity = atom_arity(atom);
    size_t len = strlen(name);
    char buf[len + 32];
    typesig_t sig = typeinst_lookup_typesig(atom);
    typeinst_t type = (sig == TYPESIG_DEFAULT? TYPEINST_NUM:
        typeinst_make_ground(sig->type));
    const char *type_name = typeinst_show(type);
    int r = snprintf(buf, sizeof(buf)-1, "%s_eq_call_%s", type_name, name);
    if (r <= 0 || r >= sizeof(buf)-1)
        panic("failed to create function constraint name");

    op = exprop_make(buf, arity+1);
    expr_t args[arity+1];
    expr_args(y, args+1);
    args[0] = x;
    expr_t e = expr(op, args);

    if (sig == TYPESIG_DEFAULT)
        return e;
    atom = expr_sym(e);
    typeinst_t sig_args[arity+1];
    memcpy(sig_args+1, sig->args, arity * sizeof(typeinst_t));
    sig_args[0] = typeinst_make_var(sig->type);
    sig = typeinst_make_typesig(arity+1, TYPEINST_BOOL, sig_args);
    if (!typeinst_declare(atom, sig))
    {
        error("(%s: %zu) failed to declare implied type for %s/%zu",
            cxt->file, cxt->line, atom_name(atom), atom_arity(arity));
        cxt->error = true;
    }
    return e;
}