Пример #1
0
 bool apply(expr const & a, expr const & b) {
     if (is_eqp(a, b))          return true;
     if (a.hash() != b.hash())  return false;
     if (a.kind() != b.kind())  return false;
     if (is_var(a))             return var_idx(a) == var_idx(b);
     if (m_cache.check(a, b))
         return true;
     switch (a.kind()) {
     case expr_kind::Var:
         lean_unreachable(); // LCOV_EXCL_LINE
     case expr_kind::Constant:
         return
             const_name(a) == const_name(b) &&
             compare(const_levels(a), const_levels(b), [](level const & l1, level const & l2) { return l1 == l2; });
     case expr_kind::Meta:
         return
             mlocal_name(a) == mlocal_name(b) &&
             apply(mlocal_type(a), mlocal_type(b));
     case expr_kind::Local:
         return
             mlocal_name(a) == mlocal_name(b) &&
             apply(mlocal_type(a), mlocal_type(b)) &&
             (!CompareBinderInfo || local_pp_name(a) == local_pp_name(b)) &&
             (!CompareBinderInfo || local_info(a) == local_info(b));
     case expr_kind::App:
         check_system();
         return
             apply(app_fn(a), app_fn(b)) &&
             apply(app_arg(a), app_arg(b));
     case expr_kind::Lambda: case expr_kind::Pi:
         check_system();
         return
             apply(binding_domain(a), binding_domain(b)) &&
             apply(binding_body(a), binding_body(b)) &&
             (!CompareBinderInfo || binding_name(a) == binding_name(b)) &&
             (!CompareBinderInfo || binding_info(a) == binding_info(b));
     case expr_kind::Let:
         check_system();
         return
             apply(let_type(a), let_type(b)) &&
             apply(let_value(a), let_value(b)) &&
             apply(let_body(a), let_body(b)) &&
             (!CompareBinderInfo || let_name(a) == let_name(b));
     case expr_kind::Sort:
         return sort_level(a) == sort_level(b);
     case expr_kind::Macro:
         check_system();
         if (macro_def(a) != macro_def(b) || macro_num_args(a) != macro_num_args(b))
             return false;
         for (unsigned i = 0; i < macro_num_args(a); i++) {
             if (!apply(macro_arg(a, i), macro_arg(b, i)))
                 return false;
         }
         return true;
     }
     lean_unreachable(); // LCOV_EXCL_LINE
 }
Пример #2
0
bool is_lt(expr const & a, expr const & b, bool use_hash) {
    if (is_eqp(a, b))                    return false;
    unsigned wa = get_weight(a);
    unsigned wb = get_weight(b);
    if (wa < wb)                         return true;
    if (wa > wb)                         return false;
    if (a.kind() != b.kind())            return a.kind() < b.kind();
    if (use_hash) {
        if (a.hash() < b.hash())         return true;
        if (a.hash() > b.hash())         return false;
    }
    if (a == b)                          return false;
    switch (a.kind()) {
    case expr_kind::Var:
        return var_idx(a) < var_idx(b);
    case expr_kind::Constant:
        if (const_name(a) != const_name(b))
            return const_name(a) < const_name(b);
        else
            return is_lt(const_levels(a), const_levels(b), use_hash);
    case expr_kind::App:
        if (app_fn(a) != app_fn(b))
            return is_lt(app_fn(a), app_fn(b), use_hash);
        else
            return is_lt(app_arg(a), app_arg(b), use_hash);
    case expr_kind::Lambda: case expr_kind::Pi:
        if (binding_domain(a) != binding_domain(b))
            return is_lt(binding_domain(a), binding_domain(b), use_hash);
        else
            return is_lt(binding_body(a), binding_body(b), use_hash);
    case expr_kind::Let:
        if (let_type(a) != let_type(b))
            return is_lt(let_type(a), let_type(b), use_hash);
        else if (let_value(a) != let_value(b))
            return is_lt(let_value(a), let_value(b), use_hash);
        else
            return is_lt(let_body(a), let_body(b), use_hash);
    case expr_kind::Sort:
        return is_lt(sort_level(a), sort_level(b), use_hash);
    case expr_kind::Local: case expr_kind::Meta:
        if (mlocal_name(a) != mlocal_name(b))
            return mlocal_name(a) < mlocal_name(b);
        else
            return is_lt(mlocal_type(a), mlocal_type(b), use_hash);
    case expr_kind::Macro:
        if (macro_def(a) != macro_def(b))
            return macro_def(a) < macro_def(b);
        if (macro_num_args(a) != macro_num_args(b))
            return macro_num_args(a) < macro_num_args(b);
        for (unsigned i = 0; i < macro_num_args(a); i++) {
            if (macro_arg(a, i) != macro_arg(b, i))
                return is_lt(macro_arg(a, i), macro_arg(b, i), use_hash);
        }
        return false;
    }
    lean_unreachable(); // LCOV_EXCL_LINE
}
Пример #3
0
bool expr_eq_fn::apply(expr const & a, expr const & b) {
    if (is_eqp(a, b))          return true;
    if (a.hash() != b.hash())  return false;
    if (a.kind() != b.kind())  return false;
    if (is_var(a))             return var_idx(a) == var_idx(b);
    if (m_counter >= LEAN_EQ_CACHE_THRESHOLD && is_shared(a) && is_shared(b)) {
        auto p = std::make_pair(a.raw(), b.raw());
        if (!m_eq_visited)
            m_eq_visited.reset(new expr_cell_pair_set);
        if (m_eq_visited->find(p) != m_eq_visited->end())
            return true;
        m_eq_visited->insert(p);
    }
    check_system("expression equality test");
    switch (a.kind()) {
    case expr_kind::Var:
        lean_unreachable(); // LCOV_EXCL_LINE
    case expr_kind::Constant:
        return
            const_name(a) == const_name(b) &&
            compare(const_levels(a), const_levels(b), [](level const & l1, level const & l2) { return l1 == l2; });
    case expr_kind::Local: case expr_kind::Meta:
        return
            mlocal_name(a) == mlocal_name(b) &&
            apply(mlocal_type(a), mlocal_type(b));
    case expr_kind::App:
        m_counter++;
        return
            apply(app_fn(a), app_fn(b)) &&
            apply(app_arg(a), app_arg(b));
    case expr_kind::Lambda: case expr_kind::Pi:
        m_counter++;
        return
            apply(binding_domain(a), binding_domain(b)) &&
            apply(binding_body(a), binding_body(b)) &&
            (!m_compare_binder_info || binding_info(a) == binding_info(b));
    case expr_kind::Sort:
        return sort_level(a) == sort_level(b);
    case expr_kind::Macro:
        m_counter++;
        if (macro_def(a) != macro_def(b) || macro_num_args(a) != macro_num_args(b))
            return false;
        for (unsigned i = 0; i < macro_num_args(a); i++) {
            if (!apply(macro_arg(a, i), macro_arg(b, i)))
                return false;
        }
        return true;
    case expr_kind::Let:
        m_counter++;
        return
            apply(let_type(a), let_type(b)) &&
            apply(let_value(a), let_value(b)) &&
            apply(let_body(a), let_body(b));
    }
    lean_unreachable(); // LCOV_EXCL_LINE
}
Пример #4
0
bool is_lt_no_level_params(expr const & a, expr const & b) {
    if (is_eqp(a, b))                    return false;
    unsigned wa = get_weight(a);
    unsigned wb = get_weight(b);
    if (wa < wb)                         return true;
    if (wa > wb)                         return false;
    if (a.kind() != b.kind())            return a.kind() < b.kind();
    switch (a.kind()) {
    case expr_kind::Var:
        return var_idx(a) < var_idx(b);
    case expr_kind::Constant:
        if (const_name(a) != const_name(b))
            return const_name(a) < const_name(b);
        else
            return is_lt_no_level_params(const_levels(a), const_levels(b));
    case expr_kind::App:
        if (is_lt_no_level_params(app_fn(a), app_fn(b)))
            return true;
        else if (is_lt_no_level_params(app_fn(b), app_fn(a)))
            return false;
        else
            return is_lt_no_level_params(app_arg(a), app_arg(b));
    case expr_kind::Lambda: case expr_kind::Pi:
        if (is_lt_no_level_params(binding_domain(a), binding_domain(b)))
            return true;
        else if (is_lt_no_level_params(binding_domain(b), binding_domain(a)))
            return false;
        else
            return is_lt_no_level_params(binding_body(a), binding_body(b));
    case expr_kind::Sort:
        return is_lt_no_level_params(sort_level(a), sort_level(b));
    case expr_kind::Local: case expr_kind::Meta:
        if (mlocal_name(a) != mlocal_name(b))
            return mlocal_name(a) < mlocal_name(b);
        else
            return is_lt_no_level_params(mlocal_type(a), mlocal_type(b));
    case expr_kind::Macro:
        if (macro_def(a) != macro_def(b))
            return macro_def(a) < macro_def(b);
        if (macro_num_args(a) != macro_num_args(b))
            return macro_num_args(a) < macro_num_args(b);
        for (unsigned i = 0; i < macro_num_args(a); i++) {
            if (is_lt_no_level_params(macro_arg(a, i), macro_arg(b, i)))
                return true;
            else if (is_lt_no_level_params(macro_arg(b, i), macro_arg(a, i)))
                return false;
        }
        return false;
    }
    lean_unreachable();
}
Пример #5
0
 /** \brief Return true iff all recursive applications in \c e are structurally smaller than \c m_pattern. */
 bool check_rhs(expr const & e) {
     switch (e.kind()) {
     case expr_kind::Var:   case expr_kind::Meta:
     case expr_kind::Local: case expr_kind::Constant:
     case expr_kind::Sort:
         return true;
     case expr_kind::Macro:
         for (unsigned i = 0; i < macro_num_args(e); i++)
             if (!check_rhs(macro_arg(e, i)))
                 return false;
         return true;
     case expr_kind::App: {
         buffer<expr> args;
         expr const & fn = get_app_args(e, args);
         if (!check_rhs(fn))
             return false;
         for (unsigned i = 0; i < args.size(); i++)
             if (!check_rhs(args[i]))
                 return false;
         if (is_local(fn) && mlocal_name(fn) == mlocal_name(m_fn)) {
             /* recusive application */
             if (m_arg_idx < args.size()) {
                 expr const & arg = args[m_arg_idx];
                 /* arg must be structurally smaller than m_pattern */
                 if (!is_lt(arg, m_pattern)) {
                     trace_struct_aux(tout() << "structural recursion on argument #" << (m_arg_idx+1)
                                      << " was not used "
                                      << "for '" << m_fn << "'\nargument #" << (m_arg_idx+1)
                                      << " in the application\n  "
                                      << e << "\nis not structurally smaller than the one occurring in "
                                      << "the equation left-hand-side\n  "
                                      << m_lhs << "\n";);
                     return false;
                 }
             } else {
Пример #6
0
void get_structure_instance_info(expr const & e,
                                 name & struct_name,
                                 optional<expr> & source,
                                 buffer<name> & field_names,
                                 buffer<expr> & field_values) {
    lean_assert(is_structure_instance(e));
    struct_name = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_struct();
    list<name> const & fns = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_field_names();
    to_buffer(fns, field_names);
    unsigned num_fields = field_names.size();
    lean_assert(macro_num_args(e) == num_fields || macro_num_args(e) == num_fields+1);
    if (num_fields < macro_num_args(e))
        source = macro_arg(e, num_fields);
    for (unsigned i = 0; i < num_fields; i++)
        field_values.push_back(macro_arg(e, i));
}
Пример #7
0
 expr apply(expr const & a) {
     check_system("max_sharing");
     auto r = m_expr_cache.find(a);
     if (r != m_expr_cache.end())
         return *r;
     expr res;
     switch (a.kind()) {
     case expr_kind::Var:
         res = a;
         break;
     case expr_kind::Constant:
         res = update_constant(a, map(const_levels(a), [&](level const & l) { return apply(l); }));
         break;
     case expr_kind::Sort:
         res = update_sort(a, apply(sort_level(a)));
         break;
     case expr_kind::App:
         res = update_app(a, apply(app_fn(a)), apply(app_arg(a)));
         break;
     case expr_kind::Lambda: case expr_kind::Pi:
         res = update_binding(a, apply(binding_domain(a)), apply(binding_body(a)));
         break;
     case expr_kind::Meta:  case expr_kind::Local:
         res = update_mlocal(a, apply(mlocal_type(a)));
         break;
     case expr_kind::Macro: {
         buffer<expr> new_args;
         for (unsigned i = 0; i < macro_num_args(a); i++)
             new_args.push_back(macro_arg(a, i));
         res = update_macro(a, new_args.size(), new_args.data());
         break;
     }}
     m_expr_cache.insert(res);
     return res;
 }
Пример #8
0
expr replace_visitor::visit_macro(expr const & e) {
    lean_assert(is_macro(e));
    buffer<expr> new_args;
    for (unsigned i = 0; i < macro_num_args(e); i++)
        new_args.push_back(visit(macro_arg(e, i)));
    return update_macro(e, new_args.size(), new_args.data());
}
Пример #9
0
 void visit_macro(expr const & e) {
     if (is_expr_quote(e) || is_pexpr_quote(e))
         return;
     if (should_visit(e)) {
         for (unsigned i = 0; i < macro_num_args(e); i++)
             visit(macro_arg(e, i));
     }
 }
Пример #10
0
void destruct_structure_instance(expr const & e, expr & t, buffer<name> & field_names,
                                 buffer<expr> & field_values, buffer<expr> & using_exprs) {
    lean_assert(is_structure_instance(e));
    t = macro_arg(e, 0);
    list<name> const & fns = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_field_names();
    unsigned num_fileds = length(fns);
    to_buffer(fns, field_names);
    for (unsigned i = 1; i < num_fileds+1; i++)
        field_values.push_back(macro_arg(e, i));
    for (unsigned i = num_fileds+1; i < macro_num_args(e); i++)
        using_exprs.push_back(macro_arg(e, i));
}
Пример #11
0
expr update_macro(expr const & e, unsigned num, expr const * args) {
    if (num == macro_num_args(e)) {
        unsigned i = 0;
        for (i = 0; i < num; i++) {
            if (!is_eqp(macro_arg(e, i), args[i]))
                break;
        }
        if (i == num)
            return e;
    }
    return mk_macro(to_macro(e)->m_definition, num, args, e.get_tag());
}
Пример #12
0
static bool is_permutation(expr const & lhs, expr const & rhs, unsigned offset, buffer<optional<unsigned>> & p) {
    if (lhs.kind() != rhs.kind())
        return false;
    switch (lhs.kind()) {
    case expr_kind::Constant: case expr_kind::Sort:
    case expr_kind::Meta: case expr_kind::Local:
        return lhs == rhs;
    case expr_kind::Var:
        if (var_idx(lhs) < offset) {
            return lhs == rhs; // locally bound variable
        } else if (var_idx(lhs) - offset < p.size()) {
            if (p[var_idx(lhs) - offset]) {
                return *(p[var_idx(lhs) - offset]) == var_idx(rhs);
            } else {
                p[var_idx(lhs) - offset] = var_idx(rhs);
                return true;
            }
        } else {
            return lhs == rhs; // free variable
        }
    case expr_kind::Lambda: case expr_kind::Pi:
        return
            is_permutation(binding_domain(lhs), binding_domain(rhs), offset, p) &&
            is_permutation(binding_body(lhs), binding_body(rhs), offset+1, p);
    case expr_kind::App:
        return
            is_permutation(app_fn(lhs), app_fn(rhs), offset, p) &&
            is_permutation(app_arg(lhs), app_arg(rhs), offset, p);
    case expr_kind::Macro:
        if (macro_def(lhs) != macro_def(rhs) ||
            macro_num_args(lhs) != macro_num_args(rhs))
            return false;
        for (unsigned i = 0; i < macro_num_args(lhs); i++) {
            if (!is_permutation(macro_arg(lhs, i), macro_arg(rhs, i), offset, p))
                return false;
        }
        return true;
    }
    lean_unreachable();
}
Пример #13
0
 expr visit_macro(expr const & e) {
     buffer<expr> new_args;
     for (unsigned i = 0; i < macro_num_args(e); i++)
         new_args.push_back(visit(macro_arg(e, i)));
     auto def = macro_def(e);
     expr r = update_macro(e, new_args.size(), new_args.data());
     if (def.trust_level() >= m_trust_lvl) {
         if (optional<expr> new_r = m_tc.expand_macro(r)) {
             return *new_r;
         } else {
             throw_generic_exception("failed to expand macro", e);
         }
     } else {
         return r;
     }
 }
Пример #14
0
 virtual expr visit_macro(expr const & e) override {
     buffer<expr> new_args;
     for (unsigned i = 0; i < macro_num_args(e); i++)
         new_args.push_back(visit(macro_arg(e, i)));
     auto def = macro_def(e);
     expr r = update_macro(e, new_args.size(), new_args.data());
     if (!m_trust_lvl || def.trust_level() >= *m_trust_lvl) {
         if (optional<expr> new_r = m_ctx.expand_macro(r)) {
             return visit(*new_r);
         } else {
             throw generic_exception(e, "failed to expand macro");
         }
     } else {
         return r;
     }
 }
Пример #15
0
void collect_locals(expr const & e, collected_locals & ls, bool restricted) {
    if (!has_local(e))
        return;
    expr_set visited;
    std::function<void(expr const & e)> visit = [&](expr const & e) {
        if (!has_local(e))
            return;
        if (restricted && is_meta(e))
            return;
        if (visited.find(e) != visited.end())
            return;
        visited.insert(e);
        switch (e.kind()) {
        case expr_kind::Var: case expr_kind::Constant: case expr_kind::Sort:
            break; // do nothing
        case expr_kind::Local:
            if (!restricted)
                visit(mlocal_type(e));
            ls.insert(e);
            break;
        case expr_kind::Meta:
            lean_assert(!restricted);
            visit(mlocal_type(e));
            break;
        case expr_kind::Macro:
            for (unsigned i = 0; i < macro_num_args(e); i++)
                visit(macro_arg(e, i));
            break;
        case expr_kind::App:
            visit(app_fn(e));
            visit(app_arg(e));
            break;
        case expr_kind::Lambda:
        case expr_kind::Pi:
            visit(binding_domain(e));
            visit(binding_body(e));
            break;
        case expr_kind::Let:
            visit(let_type(e));
            visit(let_value(e));
            visit(let_body(e));
            break;
        }
    };
    visit(e);
}
Пример #16
0
unsigned light_lt_manager::get_weight_core(expr const & e) {
    switch (e.kind()) {
    case expr_kind::Var:  case expr_kind::Constant: case expr_kind::Sort:
    case expr_kind::Meta: case expr_kind::Local:
        return 1;
    case expr_kind::Lambda: case expr_kind::Pi:
        return safe_add(1, safe_add(get_weight(binding_domain(e)), get_weight(binding_body(e))));
    case expr_kind::Macro:
        return safe_add(1, add_weight(macro_num_args(e), macro_args(e)));
    case expr_kind::App:
        buffer<expr> args;
        expr fn = get_app_args(e, args);
        if (is_constant(fn)) {
            unsigned const * light_arg = m_lrs.find(const_name(fn));
            if (light_arg && args.size() > *light_arg) return get_weight(args[*light_arg]);
        }
        return safe_add(1, safe_add(get_weight(app_fn(e)), get_weight(app_arg(e))));
    }
    lean_unreachable(); // LCOV_EXCL_LINE
}
Пример #17
0
    expr apply(expr const & e, unsigned offset) {
        bool shared = false;
        if (m_use_cache && is_shared(e)) {
            if (auto r = m_cache->find(e, offset))
                return *r;
            shared = true;
        }
        check_interrupted();
        check_memory("replace");

        if (optional<expr> r = m_f(e, offset)) {
            return save_result(e, offset, *r, shared);
        } else {
            switch (e.kind()) {
            case expr_kind::Constant: case expr_kind::Sort: case expr_kind::Var:
                return save_result(e, offset, e, shared);
            case expr_kind::Meta:     case expr_kind::Local: {
                expr new_t = apply(mlocal_type(e), offset);
                return save_result(e, offset, update_mlocal(e, new_t), shared);
            }
            case expr_kind::App: {
                expr new_f = apply(app_fn(e), offset);
                expr new_a = apply(app_arg(e), offset);
                return save_result(e, offset, update_app(e, new_f, new_a), shared);
            }
            case expr_kind::Pi: case expr_kind::Lambda: {
                expr new_d = apply(binding_domain(e), offset);
                expr new_b = apply(binding_body(e), offset+1);
                return save_result(e, offset, update_binding(e, new_d, new_b), shared);
            }
            case expr_kind::Macro: {
                buffer<expr> new_args;
                unsigned nargs = macro_num_args(e);
                for (unsigned i = 0; i < nargs; i++)
                    new_args.push_back(apply(macro_arg(e, i), offset));
                return save_result(e, offset, update_macro(e, new_args.size(), new_args.data()), shared);
            }}
            lean_unreachable();
        }
    }
Пример #18
0
bool light_lt_manager::is_lt(expr const & a, expr const & b) {
    if (is_eqp(a, b)) return false;
    unsigned wa = get_weight(a);
    unsigned wb = get_weight(b);
    if (wa < wb)                         return true;
    if (wa > wb)                         return false;
    if (is_constant(get_app_fn(a))) {
        unsigned const * light_arg = m_lrs.find(const_name(get_app_fn(a)));
        if (light_arg) {
            buffer<expr> args;
            get_app_args(a, args);
            if (args.size() > *light_arg) return is_lt(args[*light_arg], b);
        }
    }
    if (is_constant(get_app_fn(b))) {
        unsigned const * light_arg = m_lrs.find(const_name(get_app_fn(b)));
        if (light_arg) {
            buffer<expr> args;
            get_app_args(b, args);
            if (args.size() > *light_arg) return !is_lt(args[*light_arg], a);
        }
    }
    if (a.kind() != b.kind())            return a.kind() < b.kind();
    if (a == b)                          return false;
    switch (a.kind()) {
    case expr_kind::Var:
        return var_idx(a) < var_idx(b);
    case expr_kind::Constant:
        if (const_name(a) != const_name(b))
            return const_name(a) < const_name(b);
        else
            return ::lean::is_lt(const_levels(a), const_levels(b), false);
    case expr_kind::App:
        if (app_fn(a) != app_fn(b))
            return is_lt(app_fn(a), app_fn(b));
        else
            return is_lt(app_arg(a), app_arg(b));
    case expr_kind::Lambda: case expr_kind::Pi:
        if (binding_domain(a) != binding_domain(b))
            return is_lt(binding_domain(a), binding_domain(b));
        else
            return is_lt(binding_body(a), binding_body(b));
    case expr_kind::Sort:
        return ::lean::is_lt(sort_level(a), sort_level(b), false);
    case expr_kind::Local: case expr_kind::Meta:
        if (mlocal_name(a) != mlocal_name(b))
            return mlocal_name(a) < mlocal_name(b);
        else
            return is_lt(mlocal_type(a), mlocal_type(b));
    case expr_kind::Macro:
        if (macro_def(a) != macro_def(b))
            return macro_def(a) < macro_def(b);
        if (macro_num_args(a) != macro_num_args(b))
            return macro_num_args(a) < macro_num_args(b);
        for (unsigned i = 0; i < macro_num_args(a); i++) {
            if (macro_arg(a, i) != macro_arg(b, i))
                return is_lt(macro_arg(a, i), macro_arg(b, i));
        }
        return false;
    }
    lean_unreachable(); // LCOV_EXCL_LINE
}
Пример #19
0
expr dsimplify_core_fn::visit_macro(expr const & e) {
    buffer<expr> new_args;
    for (unsigned i = 0; i < macro_num_args(e); i++)
        new_args.push_back(visit(macro_arg(e, i)));
    return update_macro(e, new_args.size(), new_args.data());
}
Пример #20
0
 void check_macro(expr const & m) const {
     if (!is_macro(m) || macro_num_args(m) != 2)
         throw exception("invalid typed-expr, incorrect number of arguments");
 }
Пример #21
0
bool abstract_expr_manager::is_equal(expr const & a, expr const & b) {
    if (is_eqp(a, b))          return true;
    if (a.kind() != b.kind())  return false;
    if (is_var(a))             return var_idx(a) == var_idx(b);
    bool is_eq;
    switch (a.kind()) {
    case expr_kind::Var:
        lean_unreachable(); // LCOV_EXCL_LINE
    case expr_kind::Constant: case expr_kind::Sort:
        return a == b;
    case expr_kind::Meta: case expr_kind::Local:
        return mlocal_name(a) == mlocal_name(b) && is_equal(mlocal_type(a), mlocal_type(b));
    case expr_kind::Lambda: case expr_kind::Pi:
        if (!is_equal(binding_domain(a), binding_domain(b))) return false;
        // see comment at abstract_expr_manager::hash
        m_locals.push_back(instantiate_rev(m_tctx.mk_tmp_local(binding_domain(a)), m_locals.size(), m_locals.data()));
        is_eq = is_equal(binding_body(a), binding_body(b));
        m_locals.pop_back();
        return is_eq;
    case expr_kind::Macro:
        if (macro_def(a) != macro_def(b) || macro_num_args(a) != macro_num_args(b))
            return false;
        for (unsigned i = 0; i < macro_num_args(a); i++) {
            if (!is_equal(macro_arg(a, i), macro_arg(b, i)))
                return false;
        }
        return true;
    case expr_kind::App:
        buffer<expr> a_args, b_args;
        expr const & f_a   = get_app_args(a, a_args);
        expr const & f_b   = get_app_args(b, b_args);
        if (!is_equal(f_a, f_b))
            return false;
        if (a_args.size() != b_args.size())
            return false;
        unsigned prefix_sz = m_congr_lemma_manager.get_specialization_prefix_size(instantiate_rev(f_a, m_locals.size(), m_locals.data()), a_args.size());
        for (unsigned i = 0; i < prefix_sz; i++) {
            if (!is_equal(a_args[i], b_args[i]))
                return false;
        }
        expr new_f_a       = a;
        unsigned rest_sz   = a_args.size() - prefix_sz;
        for (unsigned i = 0; i < rest_sz; i++) {
            new_f_a = app_fn(new_f_a);
        }
        new_f_a = instantiate_rev(new_f_a, m_locals.size(), m_locals.data());
        optional<congr_lemma> congr = m_congr_lemma_manager.mk_congr(new_f_a, rest_sz);
        bool not_equal = false;
        if (!congr) {
            for (unsigned i = prefix_sz; i < a_args.size(); ++i) {
                if (!is_equal(a_args[i], b_args[i])) {
                    not_equal = true;
                    break;
                }
            }
        } else {
            lean_assert(length(congr->get_arg_kinds()) == rest_sz);
            unsigned i = prefix_sz;
            for_each(congr->get_arg_kinds(), [&](congr_arg_kind const & c_kind) {
                    if (not_equal)
                        return;
                    if (c_kind != congr_arg_kind::Cast && !is_equal(a_args[i], b_args[i])) {
                        not_equal = true;
                    }
                    i++;
                });
        }
        return !not_equal;
    }
    lean_unreachable(); // LCOV_EXCL_LINE
}
Пример #22
0
unsigned get_num_choices(expr const & e) {
    lean_assert(is_choice(e));
    return macro_num_args(e);
}
Пример #23
0
 static void check_num_args(environment const & env, expr const & m) {
     lean_assert(is_macro(m));
     if (macro_num_args(m) != 3)
         throw_kernel_exception(env, "invalid number of arguments for resolve macro", m);
 }
Пример #24
0
 void check_macro(expr const & m) const {
     if (!is_macro(m) || macro_num_args(m) != 1)
         throw exception(sstream() << "invalid '" << m_proj_name
                         << "' projection macro, incorrect number of arguments");
 }
Пример #25
0
 void check_macro(expr const & m) const {
     if (!is_macro(m) || macro_num_args(m) != 2)
         throw exception("invalid let expression");
 }