/* Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Leonardo de Moura */ #include #include #include #include "kernel/environment.h" #include "kernel/kernel_exception.h" namespace lean { /** \brief "Do nothing" normalizer extension. */ class noop_normalizer_extension : public normalizer_extension { public: virtual optional operator()(expr const &, extension_context &) const { return none_expr(); } }; environment_header::environment_header(unsigned trust_lvl, bool proof_irrel, bool eta, bool impredicative, std::unique_ptr ext): m_trust_lvl(trust_lvl), m_proof_irrel(proof_irrel), m_eta(eta), m_impredicative(impredicative), m_norm_ext(std::move(ext)) {} environment_extension::~environment_extension() {} environment_id::environment_id():m_trail(0, list()) {} environment_id::environment_id(environment_id const & ancestor, bool):m_trail(car(ancestor.m_trail) + 1, ancestor.m_trail) {} bool environment_id::is_descendant(environment_id const & id) const { list const * it = &m_trail; while (!is_nil(*it)) { if (is_eqp(*it, id.m_trail)) return true; if (car(*it) >= car(id.m_trail)) return false; it = &cdr(*it); } return false; } environment::environment(header const & h, environment_id const & ancestor, definitions const & d, extensions const & exts): m_header(h), m_id(environment_id::mk_descendant(ancestor)), m_definitions(d), m_extensions(exts) {} environment::environment(unsigned trust_lvl, bool proof_irrel, bool eta, bool impredicative): environment(trust_lvl, proof_irrel, eta, impredicative, std::unique_ptr(new noop_normalizer_extension())) {} environment::environment(unsigned trust_lvl, bool proof_irrel, bool eta, bool impredicative, std::unique_ptr ext): m_header(std::make_shared(trust_lvl, proof_irrel, eta, impredicative, std::move(ext))), m_extensions(std::make_shared()) {} environment::~environment() {} optional environment::find(name const & n) const { definition const * r = m_definitions.find(n); return r ? some_definition(*r) : none_definition(); } definition environment::get(name const & n) const { definition const * r = m_definitions.find(n); if (!r) throw_unknown_declaration(*this, n); return *r; } [[ noreturn ]] void throw_incompatible_environment(environment const & env) { throw_kernel_exception(env, "invalid declaration, it was checked/certified in an incompatible environment"); } environment environment::add(certified_definition const & d) const { if (!m_id.is_descendant(d.get_id())) throw_incompatible_environment(*this); name const & n = d.get_definition().get_name(); if (find(n)) throw_already_declared(*this, n); return environment(m_header, m_id, insert(m_definitions, n, d.get_definition()), m_extensions); } environment environment::replace(certified_definition const & t) const { if (!m_id.is_descendant(t.get_id())) throw_incompatible_environment(*this); name const & n = t.get_definition().get_name(); auto ax = find(n); if (!ax) throw_kernel_exception(*this, "invalid replacement of axiom with theorem, the environment does not have an axiom with the given name"); if (!ax->is_axiom()) throw_kernel_exception(*this, "invalid replacement of axiom with theorem, the current declaration in the environment is not an axiom"); if (!t.get_definition().is_theorem()) throw_kernel_exception(*this, "invalid replacement of axiom with theorem, the new declaration is not a theorem"); if (ax->get_type() != t.get_definition().get_type()) throw_kernel_exception(*this, "invalid replacement of axiom with theorem, the 'replace' operation can only be used when the axiom and theorem have the same type"); return environment(m_header, m_id, insert(m_definitions, n, t.get_definition()), m_extensions); } class extension_manager { std::vector> m_exts; mutex m_mutex; public: unsigned register_extension(std::shared_ptr const & ext) { lock_guard lock(m_mutex); unsigned r = m_exts.size(); m_exts.push_back(ext); return r; } bool has_ext(unsigned extid) const { return extid < m_exts.size(); } environment_extension const & get_initial(unsigned extid) { lock_guard lock(m_mutex); return *(m_exts[extid].get()); } }; static std::unique_ptr g_extension_manager; static extension_manager & get_extension_manager() { if (!g_extension_manager) g_extension_manager.reset(new extension_manager()); return *g_extension_manager; } unsigned environment::register_extension(std::shared_ptr const & initial) { return get_extension_manager().register_extension(initial); } [[ noreturn ]] void throw_invalid_extension(environment const & env) { throw_kernel_exception(env, "invalid environment extension identifier"); } environment_extension const & environment::get_extension(unsigned id) const { if (id >= get_extension_manager().has_ext(id)) throw_invalid_extension(*this); if (id < m_extensions->size() || !(*m_extensions)[id]) return get_extension_manager().get_initial(id); return *((*m_extensions)[id].get()); } environment environment::update(unsigned id, std::shared_ptr const & ext) const { if (id >= get_extension_manager().has_ext(id)) throw_invalid_extension(*this); auto new_exts = std::make_shared(*m_extensions); if (id >= new_exts->size()) new_exts->resize(id+1); (*new_exts)[id] = ext; return environment(m_header, m_id, m_definitions, new_exts); } }