// Monotonic total order on universe level terms. bool is_lt(level const & a, level const & b, bool use_hash) { if (is_eqp(a, b)) return false; unsigned da = get_depth(a); unsigned db = get_depth(b); if (da < db) return true; if (da > db) return false; if (kind(a) != kind(b)) return kind(a) < kind(b); if (use_hash) { if (hash(a) < hash(b)) return true; if (hash(a) > hash(b)) return false; } if (a == b) return false; switch (kind(a)) { case level_kind::Zero: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Param: case level_kind::Global: case level_kind::Meta: return to_param_core(a).m_id < to_param_core(b).m_id; case level_kind::Max: case level_kind::IMax: if (to_max_core(a).m_lhs != to_max_core(b).m_lhs) return is_lt(to_max_core(a).m_lhs, to_max_core(b).m_lhs, use_hash); else return is_lt(to_max_core(a).m_rhs, to_max_core(b).m_rhs, use_hash); case level_kind::Succ: return is_lt(succ_of(a), succ_of(b), use_hash); } lean_unreachable(); // LCOV_EXCL_LINE }
bool is_lt_no_level_params(level const & a, level const & b) { if (is_eqp(a, b)) return false; if (kind(a) != kind(b)) { if (kind(a) == level_kind::Param || kind(b) == level_kind::Param) return false; return kind(a) < kind(b); } switch (kind(a)) { case level_kind::Zero: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Param: return false; case level_kind::Global: return global_id(a) < global_id(b); case level_kind::Meta: return meta_id(a) < meta_id(b); case level_kind::Max: if (is_lt_no_level_params(max_lhs(a), max_lhs(b))) return true; else if (is_lt_no_level_params(max_lhs(b), max_lhs(a))) return false; else return is_lt_no_level_params(max_rhs(a), max_rhs(b)); case level_kind::IMax: if (is_lt_no_level_params(imax_lhs(a), imax_lhs(b))) return true; else if (is_lt_no_level_params(imax_lhs(b), imax_lhs(a))) return false; else return is_lt_no_level_params(imax_rhs(a), imax_rhs(b)); case level_kind::Succ: return is_lt_no_level_params(succ_of(a), succ_of(b)); } lean_unreachable(); }
bool operator==(level const & l1, level const & l2) { if (kind(l1) != kind(l2)) return false; if (hash(l1) != hash(l2)) return false; if (is_eqp(l1, l2)) return true; switch (kind(l1)) { case level_kind::Zero: return true; case level_kind::Param: case level_kind::Global: case level_kind::Meta: return to_param_core(l1).m_id == to_param_core(l2).m_id; case level_kind::Max: case level_kind::IMax: case level_kind::Succ: if (to_composite(l1).m_depth != to_composite(l2).m_depth) return false; break; } switch (kind(l1)) { case level_kind::Zero: case level_kind::Param: case level_kind::Global: case level_kind::Meta: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Max: case level_kind::IMax: return to_max_core(l1).m_lhs == to_max_core(l2).m_lhs && to_max_core(l1).m_rhs == to_max_core(l2).m_rhs; case level_kind::Succ: if (is_explicit(l1) != is_explicit(l2)) { return false; } else if (is_explicit(l1)) { lean_assert(get_depth(l1) == get_depth(l2)); // the depths are equal, then l1 and l2 must be the same universe return true; } else { return succ_of(l1) == succ_of(l2); } } lean_unreachable(); // LCOV_EXCL_LINE }
unsigned level_cases_on(vm_obj const & o, buffer<vm_obj> & data) { level const & l = to_level(o); switch (l.kind()) { case level_kind::Zero: break; case level_kind::Succ: data.push_back(to_obj(succ_of(l))); break; case level_kind::Max: data.push_back(to_obj(max_lhs(l))); data.push_back(to_obj(max_rhs(l))); break; case level_kind::IMax: data.push_back(to_obj(imax_lhs(l))); data.push_back(to_obj(imax_rhs(l))); break; case level_kind::Param: data.push_back(to_obj(param_id(l))); break; case level_kind::Global: data.push_back(to_obj(global_id(l))); break; case level_kind::Meta: data.push_back(to_obj(meta_id(l))); break; } return static_cast<unsigned>(l.kind()); }
static void print(std::ostream & out, level l) { if (is_explicit(l)) { lean_assert(get_depth(l) > 0); out << get_depth(l) - 1; } else { switch (kind(l)) { case level_kind::Zero: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Param: case level_kind::Global: out << to_param_core(l).m_id; break; case level_kind::Meta: out << "?" << meta_id(l); break; case level_kind::Succ: out << "succ "; print_child(out, succ_of(l)); break; case level_kind::Max: case level_kind::IMax: if (is_max(l)) out << "max "; else out << "imax "; print_child(out, to_max_core(l).m_lhs); // max and imax are right associative while (kind(to_max_core(l).m_rhs) == kind(l)) { l = to_max_core(l).m_rhs; out << " "; print_child(out, to_max_core(l).m_lhs); } out << " "; print_child(out, to_max_core(l).m_rhs); break; } } }
/** \brief Convert (succ^k l) into (l, k). If l is not a succ, then return (l, 0) */ pair<level, unsigned> to_offset(level l) { unsigned k = 0; while (is_succ(l)) { l = succ_of(l); k++; } return mk_pair(l, k); }
void for_each_level_fn::apply(level const & l) { if (!m_f(l)) return; switch (l.kind()) { case level_kind::Succ: apply(succ_of(l)); break; case level_kind::Max: case level_kind::IMax: apply(to_max_core(l).m_lhs); apply(to_max_core(l).m_rhs); break; case level_kind::Zero: case level_kind::Param: case level_kind::Meta: case level_kind::Global: break; } }
level replace_level_fn::apply(level const & l) { optional<level> r = m_f(l); if (r) return *r; switch (l.kind()) { case level_kind::Succ: return update_succ(l, apply(succ_of(l))); case level_kind::Max: case level_kind::IMax: return update_max(l, apply(to_max_core(l).m_lhs), apply(to_max_core(l).m_rhs)); case level_kind::Zero: case level_kind::Param: case level_kind::Meta: case level_kind::Global: return l; } lean_unreachable(); // LCOV_EXCL_LINE }
level apply(level const & l) { auto r = m_lvl_cache.find(l); if (r != m_lvl_cache.end()) return *r; level res; switch (l.kind()) { case level_kind::Zero: case level_kind::Param: case level_kind::Global: case level_kind::Meta: res = l; break; case level_kind::Succ: res = update_succ(l, apply(succ_of(l))); break; case level_kind::Max: res = update_max(l, apply(max_lhs(l)), apply(max_rhs(l))); break; case level_kind::IMax: res = update_max(l, apply(imax_lhs(l)), apply(imax_rhs(l))); break; } m_lvl_cache.insert(res); return res; }
level update_succ(level const & l, level const & new_arg) { if (is_eqp(succ_of(l), new_arg)) return l; else return mk_succ(new_arg); }