2013-07-29 05:34:39 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
2013-11-18 02:11:44 +00:00
|
|
|
#include <cstdlib>
|
2013-07-29 05:34:39 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
2013-10-26 18:07:06 +00:00
|
|
|
#include <tuple>
|
2013-12-29 01:31:35 +00:00
|
|
|
#include <fstream>
|
|
|
|
#include <string>
|
2013-12-30 05:59:57 +00:00
|
|
|
#include <utility>
|
2013-12-09 22:56:48 +00:00
|
|
|
#include "util/thread.h"
|
2013-09-13 03:04:10 +00:00
|
|
|
#include "util/safe_arith.h"
|
2013-11-18 17:52:47 +00:00
|
|
|
#include "util/realpath.h"
|
2013-12-20 18:45:44 +00:00
|
|
|
#include "util/sstream.h"
|
2013-12-29 01:31:35 +00:00
|
|
|
#include "util/lean_path.h"
|
2013-12-29 11:43:45 +00:00
|
|
|
#include "util/flet.h"
|
2013-11-19 19:24:02 +00:00
|
|
|
#include "kernel/for_each_fn.h"
|
2013-11-19 21:03:46 +00:00
|
|
|
#include "kernel/find_fn.h"
|
2013-09-13 03:04:10 +00:00
|
|
|
#include "kernel/kernel_exception.h"
|
|
|
|
#include "kernel/environment.h"
|
2013-11-12 04:29:53 +00:00
|
|
|
#include "kernel/threadsafe_environment.h"
|
2013-09-13 03:04:10 +00:00
|
|
|
#include "kernel/type_checker.h"
|
|
|
|
#include "kernel/normalizer.h"
|
2014-01-07 00:46:11 +00:00
|
|
|
#include "kernel/universe_constraints.h"
|
2014-01-30 00:31:00 +00:00
|
|
|
#include "kernel/kernel.h"
|
2013-12-29 01:31:35 +00:00
|
|
|
#include "version.h"
|
2013-07-29 05:34:39 +00:00
|
|
|
|
|
|
|
namespace lean {
|
2013-12-28 22:39:10 +00:00
|
|
|
class set_opaque_command : public neutral_object_cell {
|
|
|
|
name m_obj_name;
|
|
|
|
bool m_opaque;
|
|
|
|
public:
|
|
|
|
set_opaque_command(name const & n, bool opaque):m_obj_name(n), m_opaque(opaque) {}
|
|
|
|
virtual ~set_opaque_command() {}
|
2014-01-09 16:33:52 +00:00
|
|
|
virtual char const * keyword() const { return "set_opaque"; }
|
2013-12-30 03:19:24 +00:00
|
|
|
virtual void write(serializer & s) const { s << "Opa" << m_obj_name << m_opaque; }
|
2014-01-01 21:16:44 +00:00
|
|
|
name const & get_obj_name() const { return m_obj_name; }
|
|
|
|
bool get_flag() const { return m_opaque; }
|
2013-12-28 22:39:10 +00:00
|
|
|
};
|
|
|
|
static void read_set_opaque(environment const & env, io_state const &, deserializer & d) {
|
|
|
|
name n = read_name(d);
|
|
|
|
bool o = d.read_bool();
|
|
|
|
env->set_opaque(n, o);
|
|
|
|
}
|
2013-12-30 03:19:24 +00:00
|
|
|
static object_cell::register_deserializer_fn set_opaque_ds("Opa", read_set_opaque);
|
2013-12-28 22:39:10 +00:00
|
|
|
|
2014-01-01 21:16:44 +00:00
|
|
|
bool is_set_opaque(object const & obj) {
|
|
|
|
return dynamic_cast<set_opaque_command const *>(obj.cell());
|
|
|
|
}
|
|
|
|
|
|
|
|
name const & get_set_opaque_id(object const & obj) {
|
|
|
|
lean_assert(is_set_opaque(obj));
|
|
|
|
return static_cast<set_opaque_command const *>(obj.cell())->get_obj_name();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool get_set_opaque_flag(object const & obj) {
|
|
|
|
lean_assert(is_set_opaque(obj));
|
|
|
|
return static_cast<set_opaque_command const *>(obj.cell())->get_flag();
|
|
|
|
}
|
|
|
|
|
2013-12-29 01:31:35 +00:00
|
|
|
class import_command : public neutral_object_cell {
|
|
|
|
std::string m_mod_name;
|
|
|
|
public:
|
|
|
|
import_command(std::string const & n):m_mod_name(n) {}
|
|
|
|
virtual ~import_command() {}
|
2014-01-05 20:05:08 +00:00
|
|
|
virtual char const * keyword() const { return "import"; }
|
|
|
|
virtual void write(serializer & s) const { s << "import" << m_mod_name; }
|
2013-12-29 03:20:04 +00:00
|
|
|
std::string const & get_module() const { return m_mod_name; }
|
2013-12-29 01:31:35 +00:00
|
|
|
};
|
|
|
|
static void read_import(environment const & env, io_state const & ios, deserializer & d) {
|
|
|
|
std::string n = d.read_string();
|
|
|
|
env->import(n, ios);
|
|
|
|
}
|
2014-01-05 20:05:08 +00:00
|
|
|
static object_cell::register_deserializer_fn import_ds("import", read_import);
|
2013-12-29 01:31:35 +00:00
|
|
|
|
|
|
|
class end_import_mark : public neutral_object_cell {
|
|
|
|
public:
|
|
|
|
end_import_mark() {}
|
|
|
|
virtual ~end_import_mark() {}
|
|
|
|
virtual char const * keyword() const { return "EndImport"; }
|
|
|
|
virtual void write(serializer &) const {}
|
|
|
|
};
|
|
|
|
|
|
|
|
// For Importing builtin modules
|
|
|
|
class begin_import_mark : public neutral_object_cell {
|
|
|
|
public:
|
|
|
|
begin_import_mark() {}
|
|
|
|
virtual ~begin_import_mark() {}
|
|
|
|
virtual char const * keyword() const { return "BeginImport"; }
|
|
|
|
virtual void write(serializer &) const {}
|
|
|
|
};
|
|
|
|
|
|
|
|
bool is_begin_import(object const & obj) {
|
2013-12-29 03:20:04 +00:00
|
|
|
return dynamic_cast<import_command const*>(obj.cell());
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<std::string> get_imported_module(object const & obj) {
|
|
|
|
if (is_begin_import(obj)) {
|
|
|
|
return optional<std::string>(static_cast<import_command const*>(obj.cell())->get_module());
|
|
|
|
} else {
|
|
|
|
return optional<std::string>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_begin_builtin_import(object const & obj) {
|
|
|
|
return dynamic_cast<begin_import_mark const*>(obj.cell());
|
2013-12-29 01:31:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_end_import(object const & obj) {
|
|
|
|
return dynamic_cast<end_import_mark const*>(obj.cell());
|
|
|
|
}
|
|
|
|
|
2013-11-07 03:21:22 +00:00
|
|
|
class extension_factory {
|
2013-12-13 00:33:31 +00:00
|
|
|
std::vector<environment_cell::mk_extension> m_makers;
|
|
|
|
mutex m_makers_mutex;
|
2013-11-07 03:21:22 +00:00
|
|
|
public:
|
2013-12-13 00:33:31 +00:00
|
|
|
unsigned register_extension(environment_cell::mk_extension mk) {
|
2013-12-09 22:56:48 +00:00
|
|
|
lock_guard<mutex> lock(m_makers_mutex);
|
2013-11-07 03:21:22 +00:00
|
|
|
unsigned r = m_makers.size();
|
|
|
|
m_makers.push_back(mk);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
std::unique_ptr<environment_extension> mk(unsigned extid) {
|
2013-12-09 22:56:48 +00:00
|
|
|
lock_guard<mutex> lock(m_makers_mutex);
|
2013-11-07 03:21:22 +00:00
|
|
|
return m_makers[extid]();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static std::unique_ptr<extension_factory> g_extension_factory;
|
|
|
|
static extension_factory & get_extension_factory() {
|
|
|
|
if (!g_extension_factory)
|
|
|
|
g_extension_factory.reset(new extension_factory());
|
|
|
|
return *g_extension_factory;
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
unsigned environment_cell::register_extension(mk_extension mk) {
|
2013-11-07 03:21:22 +00:00
|
|
|
return get_extension_factory().register_extension(mk);
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment environment_cell::env() const {
|
|
|
|
lean_assert(!m_this.expired()); // it is not possible to expire since it is a reference to this object
|
|
|
|
lean_assert(this == m_this.lock().get());
|
|
|
|
return environment(m_this.lock());
|
|
|
|
}
|
2013-08-04 23:07:37 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment environment_cell::parent() const {
|
|
|
|
lean_assert(has_parent());
|
|
|
|
return environment(m_parent);
|
|
|
|
}
|
2013-07-29 05:34:39 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment environment_cell::mk_child() const {
|
|
|
|
return environment(m_this.lock(), true);
|
|
|
|
}
|
2013-08-16 22:09:26 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension & environment_cell::get_extension_core(unsigned extid) {
|
|
|
|
if (extid >= m_extensions.size())
|
|
|
|
m_extensions.resize(extid+1);
|
|
|
|
if (!m_extensions[extid]) {
|
|
|
|
std::unique_ptr<environment_extension> ext = get_extension_factory().mk(extid);
|
|
|
|
ext->m_extid = extid;
|
|
|
|
ext->m_env = this;
|
|
|
|
m_extensions[extid].swap(ext);
|
2013-08-16 22:09:26 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
return *(m_extensions[extid].get());
|
|
|
|
}
|
2013-08-16 22:09:26 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension const & environment_cell::get_extension_core(unsigned extid) const {
|
|
|
|
return const_cast<environment_cell *>(this)->get_extension_core(extid);
|
|
|
|
}
|
2013-08-16 22:09:26 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
unsigned environment_cell::get_max_weight(expr const & e) {
|
|
|
|
unsigned w = 0;
|
|
|
|
auto proc = [&](expr const & c, unsigned) {
|
|
|
|
if (is_constant(c)) {
|
|
|
|
optional<object> obj = get_object_core(const_name(c));
|
|
|
|
if (obj)
|
|
|
|
w = std::max(w, obj->get_weight());
|
2013-08-16 22:09:26 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
for_each_fn<decltype(proc)> visitor(proc);
|
|
|
|
visitor(e);
|
|
|
|
return w;
|
|
|
|
}
|
2013-08-16 22:09:26 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Throw exception if environment or its ancestors already have an object with the given name. */
|
|
|
|
void environment_cell::check_name_core(name const & n) {
|
|
|
|
if (has_parent())
|
|
|
|
m_parent->check_name_core(n);
|
|
|
|
if (m_object_dictionary.find(n) != m_object_dictionary.end())
|
|
|
|
throw already_declared_exception(env(), n);
|
|
|
|
}
|
2013-08-16 22:09:26 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
void environment_cell::check_name(name const & n) {
|
|
|
|
if (has_children())
|
|
|
|
throw read_only_environment_exception(env());
|
|
|
|
check_name_core(n);
|
|
|
|
}
|
2013-07-29 05:34:39 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Store new named object inside internal data-structures */
|
|
|
|
void environment_cell::register_named_object(object const & new_obj) {
|
|
|
|
m_objects.push_back(new_obj);
|
|
|
|
m_object_dictionary.insert(std::make_pair(new_obj.get_name(), new_obj));
|
|
|
|
}
|
2013-07-29 05:34:39 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Return the object named \c n in the environment or its
|
|
|
|
ancestors. Return null object if there is no object with the
|
|
|
|
given name.
|
|
|
|
*/
|
|
|
|
optional<object> environment_cell::get_object_core(name const & n) const {
|
|
|
|
auto it = m_object_dictionary.find(n);
|
|
|
|
if (it == m_object_dictionary.end()) {
|
2013-08-05 00:47:54 +00:00
|
|
|
if (has_parent())
|
2013-12-13 00:33:31 +00:00
|
|
|
return m_parent->get_object_core(n);
|
2013-08-05 00:47:54 +00:00
|
|
|
else
|
2013-12-13 00:33:31 +00:00
|
|
|
return none_object();
|
|
|
|
} else {
|
|
|
|
return some_object(it->second);
|
2013-08-13 22:13:54 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
}
|
2013-08-13 22:13:54 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
object environment_cell::get_object(name const & n) const {
|
|
|
|
optional<object> obj = get_object_core(n);
|
|
|
|
if (obj) {
|
|
|
|
return *obj;
|
|
|
|
} else {
|
|
|
|
throw unknown_object_exception(env(), n);
|
2013-08-06 03:06:07 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
}
|
2013-08-06 03:06:07 +00:00
|
|
|
|
2014-01-07 23:39:45 +00:00
|
|
|
class universes {
|
|
|
|
public:
|
2014-01-07 00:46:11 +00:00
|
|
|
std::vector<level> m_uvars;
|
|
|
|
universe_constraints m_constraints;
|
|
|
|
};
|
|
|
|
|
|
|
|
universes & environment_cell::get_rw_universes() {
|
|
|
|
if (!m_universes) {
|
|
|
|
lean_assert(has_parent());
|
|
|
|
m_universes.reset(new universes(m_parent->get_rw_universes()));
|
|
|
|
}
|
|
|
|
return *m_universes;
|
|
|
|
}
|
|
|
|
|
|
|
|
universes const & environment_cell::get_ro_universes() const {
|
|
|
|
if (m_universes) {
|
|
|
|
return *m_universes;
|
|
|
|
} else {
|
|
|
|
lean_assert(has_parent());
|
|
|
|
return m_parent->get_ro_universes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
universe_constraints & environment_cell::get_rw_ucs() {
|
|
|
|
return get_rw_universes().m_constraints;
|
|
|
|
}
|
|
|
|
|
|
|
|
universe_constraints const & environment_cell::get_ro_ucs() const {
|
|
|
|
return get_ro_universes().m_constraints;
|
2013-12-13 00:33:31 +00:00
|
|
|
}
|
|
|
|
|
2014-01-07 01:13:13 +00:00
|
|
|
optional<int> environment_cell::get_universe_distance(name const & u1, name const & u2) const {
|
|
|
|
return get_ro_ucs().get_distance(u1, u2);
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Return true iff l1 >= l2 + k by asserted universe constraints. */
|
|
|
|
bool environment_cell::is_ge(level const & l1, level const & l2, int k) const {
|
|
|
|
if (l1 == l2)
|
|
|
|
return k <= 0;
|
|
|
|
switch (kind(l2)) {
|
|
|
|
case level_kind::UVar:
|
|
|
|
switch (kind(l1)) {
|
2014-01-07 00:46:11 +00:00
|
|
|
case level_kind::UVar: return get_ro_ucs().is_implied(uvar_name(l1), uvar_name(l2), k);
|
2013-12-13 00:33:31 +00:00
|
|
|
case level_kind::Lift: return is_ge(lift_of(l1), l2, safe_sub(k, lift_offset(l1)));
|
|
|
|
case level_kind::Max: return std::any_of(max_begin_levels(l1), max_end_levels(l1), [&](level const & l) { return is_ge(l, l2, k); });
|
2013-09-04 15:53:00 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
case level_kind::Lift: return is_ge(l1, lift_of(l2), safe_add(k, lift_offset(l2)));
|
|
|
|
case level_kind::Max: return std::all_of(max_begin_levels(l2), max_end_levels(l2), [&](level const & l) { return is_ge(l1, l, k); });
|
2013-09-04 15:30:04 +00:00
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
lean_unreachable(); // LCOV_EXCL_LINE
|
|
|
|
}
|
2013-09-04 15:30:04 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Return true iff l1 >= l2 is implied by asserted universe constraints. */
|
|
|
|
bool environment_cell::is_ge(level const & l1, level const & l2) const {
|
2014-01-07 00:46:11 +00:00
|
|
|
return is_ge(l1, l2, 0);
|
2013-12-13 00:33:31 +00:00
|
|
|
}
|
2013-08-06 03:06:07 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add a new universe variable */
|
|
|
|
level environment_cell::add_uvar_core(name const & n) {
|
|
|
|
check_name(n);
|
2014-01-07 00:46:11 +00:00
|
|
|
universes & u = get_rw_universes();
|
|
|
|
u.m_constraints.add_var(n);
|
2013-12-13 00:33:31 +00:00
|
|
|
level r(n);
|
2014-01-07 00:46:11 +00:00
|
|
|
u.m_uvars.push_back(r);
|
2013-12-13 00:33:31 +00:00
|
|
|
return r;
|
|
|
|
}
|
2013-08-05 03:52:14 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Add all basic constraints implied by n >= l + k
|
2013-08-06 03:06:07 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
A basic constraint is a constraint of the form u >= v + k
|
|
|
|
where u and v are universe variables.
|
|
|
|
*/
|
2014-01-07 00:46:11 +00:00
|
|
|
void environment_cell::add_constraints(name const & n, level const & l, int k) {
|
2013-12-13 00:33:31 +00:00
|
|
|
switch (kind(l)) {
|
2014-01-07 00:46:11 +00:00
|
|
|
case level_kind::UVar: get_rw_ucs().add_constraint(n, uvar_name(l), k); return;
|
2013-12-13 00:33:31 +00:00
|
|
|
case level_kind::Lift: add_constraints(n, lift_of(l), safe_add(k, lift_offset(l))); return;
|
|
|
|
case level_kind::Max: std::for_each(max_begin_levels(l), max_end_levels(l), [&](level const & l1) { add_constraints(n, l1, k); }); return;
|
|
|
|
}
|
|
|
|
lean_unreachable(); // LCOV_EXCL_LINE
|
|
|
|
}
|
|
|
|
|
2014-01-07 00:46:11 +00:00
|
|
|
/**
|
|
|
|
\brief Check if n >= l + k is consistent with the existing constraints.
|
|
|
|
*/
|
|
|
|
void environment_cell::check_consistency(name const & n, level const & l, int k) const {
|
|
|
|
switch (kind(l)) {
|
|
|
|
case level_kind::UVar:
|
2014-01-30 00:31:00 +00:00
|
|
|
if (l == ty_level(TypeU))
|
|
|
|
throw kernel_exception(env(), sstream() << "invalid universe constraint: " << n << " >= " << l << " + " << k
|
|
|
|
<< ", several modules in Lean assume that " << l << " is the maximal universe");
|
2014-01-07 00:46:11 +00:00
|
|
|
if (!get_ro_ucs().is_consistent(n, uvar_name(l), k))
|
|
|
|
throw kernel_exception(env(), sstream() << "universe constraint inconsistency: " << n << " >= " << l << " + " << k);
|
2014-01-07 21:43:22 +00:00
|
|
|
if (get_ro_ucs().overflows(n, uvar_name(l), k))
|
|
|
|
throw kernel_exception(env(), sstream() << "universe constraint produces an integer overflow: " << n << " >= " << l << " + " << k);
|
2014-01-07 00:46:11 +00:00
|
|
|
return;
|
|
|
|
case level_kind::Lift: check_consistency(n, lift_of(l), safe_add(k, lift_offset(l))); return;
|
|
|
|
case level_kind::Max: std::for_each(max_begin_levels(l), max_end_levels(l), [&](level const & l1) { check_consistency(n, l1, k); }); return;
|
|
|
|
}
|
|
|
|
lean_unreachable(); // LCOV_EXCL_LINE
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add a new universe variable with constraint n >= l */
|
2014-01-07 00:46:11 +00:00
|
|
|
level environment_cell::add_uvar_cnstr(name const & n, level const & l) {
|
2013-12-13 00:33:31 +00:00
|
|
|
if (has_children())
|
|
|
|
throw read_only_environment_exception(env());
|
2014-01-07 00:46:11 +00:00
|
|
|
level r;
|
|
|
|
auto const & uvs = get_ro_universes().m_uvars;
|
|
|
|
auto it = std::find_if(uvs.begin(), uvs.end(), [&](level const & l) { return uvar_name(l) == n; });
|
2014-01-30 00:31:00 +00:00
|
|
|
bool new_universe;
|
2014-01-07 21:43:22 +00:00
|
|
|
check_consistency(n, l, 0);
|
2014-01-07 00:46:11 +00:00
|
|
|
if (it == uvs.end()) {
|
|
|
|
r = add_uvar_core(n);
|
2014-01-30 00:31:00 +00:00
|
|
|
new_universe = true;
|
2014-01-07 00:46:11 +00:00
|
|
|
} else {
|
|
|
|
// universe n already exists, we must check consistency of the new constraint.
|
|
|
|
r = *it;
|
2014-01-30 00:31:00 +00:00
|
|
|
new_universe = false;
|
2014-01-07 00:46:11 +00:00
|
|
|
}
|
2014-01-07 23:57:36 +00:00
|
|
|
m_objects.push_back(mk_uvar_cnstr(n, l));
|
2014-01-07 00:46:11 +00:00
|
|
|
add_constraints(n, l, 0);
|
2014-01-30 00:31:00 +00:00
|
|
|
name const & Uname = uvar_name(ty_level(TypeU));
|
|
|
|
if (new_universe && n != Uname && !is_ge(ty_level(TypeU), r, 1)) {
|
|
|
|
// In Lean, U is the maximal universe, several Lean modules assume that,
|
|
|
|
// and the kernel axioms are all with respect to U.
|
|
|
|
// So, we force all other universes to smaller than U
|
|
|
|
add_uvar_cnstr(Uname, r+1);
|
|
|
|
}
|
2013-12-13 00:33:31 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
\brief Return the universe variable with given name. Throw an
|
|
|
|
exception if the environment and its ancestors do not
|
|
|
|
contain a universe variable named \c n.
|
|
|
|
*/
|
|
|
|
level environment_cell::get_uvar(name const & n) const {
|
2014-01-07 00:46:11 +00:00
|
|
|
auto const & uvs = get_ro_universes().m_uvars;
|
|
|
|
auto it = std::find_if(uvs.begin(), uvs.end(), [&](level const & l) { return uvar_name(l) == n; });
|
|
|
|
if (it == uvs.end())
|
|
|
|
throw unknown_universe_variable_exception(env(), n);
|
|
|
|
else
|
|
|
|
return *it;
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Initialize the set of universe variables with bottom
|
|
|
|
*/
|
|
|
|
void environment_cell::init_uvars() {
|
2014-01-07 00:46:11 +00:00
|
|
|
m_universes.reset(new universes());
|
|
|
|
universes & u = get_rw_universes();
|
|
|
|
level bottom;
|
|
|
|
u.m_uvars.push_back(bottom);
|
|
|
|
u.m_constraints.add_var(uvar_name(bottom));
|
2013-07-29 05:34:39 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
The kernel should *not* accept expressions containing cached types.
|
|
|
|
Reason: Cached types may introduce unsoundness.
|
|
|
|
For example, in the environment env, the constant x may have type T.
|
|
|
|
Now suppose we are trying to add a new definition D that contains x,
|
|
|
|
and x is associated with a cached type T'. The cached type may allow
|
|
|
|
us to accept a definition that is type incorrect with respect to env.
|
|
|
|
*/
|
|
|
|
void environment_cell::check_no_cached_type(expr const & e) {
|
|
|
|
if (find(e, [](expr const & a) { return is_constant(a) && const_type(a); }))
|
2014-01-07 22:34:21 +00:00
|
|
|
throw kernel_exception(env(), "expression has a constant with a cached type, this is a bug in one of Lean tactics and/or solvers"); // LCOV_EXCL_LINE
|
2013-11-17 02:35:17 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Throw an exception if \c t is not a type or type of \c
|
|
|
|
v is not convertible to \c t.
|
|
|
|
*/
|
|
|
|
void environment_cell::check_type(name const & n, expr const & t, expr const & v) {
|
2013-12-29 11:43:45 +00:00
|
|
|
if (m_type_check) {
|
|
|
|
m_type_checker->check_type(t);
|
|
|
|
expr v_t = m_type_checker->check(v);
|
|
|
|
if (!m_type_checker->is_convertible(v_t, t))
|
|
|
|
throw def_type_mismatch_exception(env(), n, t, v, v_t);
|
|
|
|
}
|
2013-07-29 05:34:39 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Throw exception if it is not a valid new definition */
|
|
|
|
void environment_cell::check_new_definition(name const & n, expr const & t, expr const & v) {
|
|
|
|
check_name(n);
|
|
|
|
check_type(n, t, v);
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add a new builtin value to this environment */
|
|
|
|
void environment_cell::add_builtin(expr const & v) {
|
|
|
|
if (!is_value(v))
|
2014-01-07 22:34:21 +00:00
|
|
|
throw invalid_builtin_value_declaration(env(), v); // LCOV_EXCL_LINE
|
2013-12-13 00:33:31 +00:00
|
|
|
name const & n = to_value(v).get_name();
|
|
|
|
check_name(n);
|
|
|
|
name const & u = to_value(v).get_unicode_name();
|
|
|
|
check_name(u);
|
|
|
|
register_named_object(mk_builtin(v));
|
|
|
|
if (u != n) {
|
2013-12-30 05:59:57 +00:00
|
|
|
auxiliary_section([&]() {
|
|
|
|
add_definition(u, to_value(v).get_type(), mk_constant(n), false);
|
|
|
|
});
|
2013-12-13 00:33:31 +00:00
|
|
|
}
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add a new builtin value set to this environment */
|
|
|
|
void environment_cell::add_builtin_set(expr const & r) {
|
|
|
|
if (!is_value(r))
|
2014-01-07 22:34:21 +00:00
|
|
|
throw invalid_builtin_value_declaration(env(), r); // LCOV_EXCL_LINE
|
2013-12-13 00:33:31 +00:00
|
|
|
check_name(to_value(r).get_name());
|
|
|
|
register_named_object(mk_builtin_set(r));
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add new definition. */
|
|
|
|
void environment_cell::add_definition(name const & n, expr const & t, expr const & v, bool opaque) {
|
|
|
|
check_no_cached_type(t);
|
|
|
|
check_no_cached_type(v);
|
|
|
|
check_new_definition(n, t, v);
|
|
|
|
unsigned w = get_max_weight(v) + 1;
|
2013-12-28 22:39:10 +00:00
|
|
|
register_named_object(mk_definition(n, t, v, w));
|
|
|
|
if (opaque)
|
|
|
|
set_opaque(n, opaque);
|
2013-08-04 23:07:37 +00:00
|
|
|
}
|
2013-08-09 22:33:34 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/**
|
|
|
|
\brief Add new definition.
|
|
|
|
The type of the new definition is the type of \c v.
|
|
|
|
*/
|
|
|
|
void environment_cell::add_definition(name const & n, expr const & v, bool opaque) {
|
|
|
|
check_no_cached_type(v);
|
|
|
|
check_name(n);
|
2013-12-29 11:43:45 +00:00
|
|
|
expr v_t;
|
|
|
|
if (m_type_check)
|
|
|
|
v_t = m_type_checker->check(v);
|
|
|
|
else
|
|
|
|
v_t = m_type_checker->infer_type(v);
|
2013-12-13 00:33:31 +00:00
|
|
|
unsigned w = get_max_weight(v) + 1;
|
2013-12-28 22:39:10 +00:00
|
|
|
register_named_object(mk_definition(n, v_t, v, w));
|
|
|
|
if (opaque)
|
|
|
|
set_opaque(n, opaque);
|
2013-08-09 22:33:34 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add new theorem. */
|
|
|
|
void environment_cell::add_theorem(name const & n, expr const & t, expr const & v) {
|
|
|
|
check_no_cached_type(t);
|
|
|
|
check_no_cached_type(v);
|
|
|
|
check_new_definition(n, t, v);
|
|
|
|
register_named_object(mk_theorem(n, t, v));
|
2013-08-09 22:33:34 +00:00
|
|
|
}
|
|
|
|
|
2013-12-20 18:45:44 +00:00
|
|
|
void environment_cell::set_opaque(name const & n, bool opaque) {
|
|
|
|
auto obj = find_object(n);
|
|
|
|
if (!obj || !obj->is_definition())
|
|
|
|
throw kernel_exception(env(), sstream() << "set_opaque failed, '" << n << "' is not a definition");
|
|
|
|
obj->set_opaque(opaque);
|
2013-12-28 22:39:10 +00:00
|
|
|
add_neutral_object(new set_opaque_command(n, opaque));
|
2013-12-20 18:45:44 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add new axiom. */
|
|
|
|
void environment_cell::add_axiom(name const & n, expr const & t) {
|
|
|
|
check_no_cached_type(t);
|
|
|
|
check_name(n);
|
2013-12-29 11:43:45 +00:00
|
|
|
if (m_type_check)
|
|
|
|
m_type_checker->check_type(t);
|
2013-12-13 00:33:31 +00:00
|
|
|
register_named_object(mk_axiom(n, t));
|
2013-08-05 00:47:54 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
/** \brief Add new variable. */
|
|
|
|
void environment_cell::add_var(name const & n, expr const & t) {
|
|
|
|
check_no_cached_type(t);
|
|
|
|
check_name(n);
|
2013-12-29 11:43:45 +00:00
|
|
|
if (m_type_check)
|
|
|
|
m_type_checker->check_type(t);
|
2013-12-13 00:33:31 +00:00
|
|
|
register_named_object(mk_var_decl(n, t));
|
2013-09-04 15:30:04 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
void environment_cell::add_neutral_object(neutral_object_cell * o) {
|
|
|
|
m_objects.push_back(mk_neutral(o));
|
2013-09-04 15:30:04 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
unsigned environment_cell::get_num_objects(bool local) const {
|
|
|
|
if (local || !has_parent()) {
|
|
|
|
return m_objects.size();
|
|
|
|
} else {
|
|
|
|
return m_objects.size() + m_parent->get_num_objects(false);
|
|
|
|
}
|
2013-08-05 03:52:14 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
object const & environment_cell::get_object(unsigned i, bool local) const {
|
|
|
|
if (local || !has_parent()) {
|
|
|
|
return m_objects[i];
|
|
|
|
} else {
|
|
|
|
unsigned num_parent_objects = m_parent->get_num_objects(false);
|
|
|
|
if (i >= num_parent_objects)
|
|
|
|
return m_objects[i - num_parent_objects];
|
|
|
|
else
|
|
|
|
return m_parent->get_object(i, false);
|
|
|
|
}
|
2013-08-06 19:24:20 +00:00
|
|
|
}
|
|
|
|
|
2013-12-22 19:51:38 +00:00
|
|
|
expr environment_cell::type_check(expr const & e, context const & ctx) const {
|
|
|
|
return m_type_checker->check(e, ctx);
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
expr environment_cell::infer_type(expr const & e, context const & ctx) const {
|
|
|
|
return m_type_checker->infer_type(e, ctx);
|
2013-08-05 03:52:14 +00:00
|
|
|
}
|
|
|
|
|
refactor(kernel): add unfold_opaque flag to normalizer, modify how type checker uses the opaque flag, remove hidden_defs, and mark most builtin definitions as opaque
After this commit, in the type checker, when checking convertability, we first compute a normal form without expanding opaque terms.
If the terms are convertible, then we are done, and saved a lot of time by not expanding unnecessary definitions.
If they are not, instead of throwing an error, we try again expanding the opaque terms.
This seems to be the best of both worlds.
The opaque flag is a hint for the type checker, but it would never prevent us from type checking a valid term.
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2013-12-20 20:47:36 +00:00
|
|
|
expr environment_cell::normalize(expr const & e, context const & ctx, bool unfold_opaque) const {
|
|
|
|
return m_type_checker->get_normalizer()(e, ctx, unfold_opaque);
|
2013-08-06 03:06:07 +00:00
|
|
|
}
|
|
|
|
|
2014-01-15 19:02:47 +00:00
|
|
|
bool environment_cell::is_proposition(expr const & e, context const & ctx) const {
|
|
|
|
return m_type_checker->is_proposition(e, ctx);
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
bool environment_cell::already_imported(name const & n) const {
|
|
|
|
if (m_imported_modules.find(n) != m_imported_modules.end())
|
|
|
|
return true;
|
|
|
|
else if (has_parent())
|
|
|
|
return m_parent->already_imported(n);
|
|
|
|
else
|
|
|
|
return false;
|
2013-08-15 01:16:11 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
bool environment_cell::mark_imported_core(name n) {
|
|
|
|
if (already_imported(n)) {
|
|
|
|
return false;
|
|
|
|
} else if (has_children()) {
|
|
|
|
throw read_only_environment_exception(env());
|
|
|
|
} else {
|
|
|
|
m_imported_modules.insert(n);
|
|
|
|
return true;
|
|
|
|
}
|
2013-08-05 03:52:14 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
bool environment_cell::mark_imported(char const * fname) {
|
|
|
|
return mark_imported_core(name(realpath(fname)));
|
2013-08-17 17:55:42 +00:00
|
|
|
}
|
|
|
|
|
2013-12-29 01:31:35 +00:00
|
|
|
void environment_cell::auxiliary_section(std::function<void()> fn) {
|
|
|
|
add_neutral_object(new begin_import_mark());
|
|
|
|
try {
|
|
|
|
fn();
|
|
|
|
add_neutral_object(new end_import_mark());
|
|
|
|
} catch (...) {
|
|
|
|
add_neutral_object(new end_import_mark());
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-29 11:43:45 +00:00
|
|
|
void environment_cell::set_trusted_imported(bool flag) {
|
|
|
|
m_trust_imported = flag;
|
|
|
|
}
|
|
|
|
|
2013-12-29 01:31:35 +00:00
|
|
|
static char const * g_olean_header = "oleanfile";
|
|
|
|
static char const * g_olean_end_file = "EndFile";
|
|
|
|
void environment_cell::export_objects(std::string const & fname) {
|
2013-12-31 02:20:36 +00:00
|
|
|
std::ofstream out(fname, std::ofstream::binary);
|
2013-12-29 01:31:35 +00:00
|
|
|
serializer s(out);
|
|
|
|
s << g_olean_header << LEAN_VERSION_MAJOR << LEAN_VERSION_MINOR;
|
|
|
|
auto it = begin_objects();
|
|
|
|
auto end = end_objects();
|
|
|
|
unsigned num_imports = 0;
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
object const & obj = *it;
|
|
|
|
if (dynamic_cast<import_command const*>(obj.cell())) {
|
|
|
|
if (num_imports == 0)
|
|
|
|
obj.write(s);
|
|
|
|
num_imports++;
|
|
|
|
} else if (dynamic_cast<end_import_mark const*>(obj.cell())) {
|
|
|
|
lean_assert(num_imports > 0);
|
|
|
|
num_imports--;
|
|
|
|
} else if (dynamic_cast<begin_import_mark const*>(obj.cell())) {
|
|
|
|
num_imports++;
|
|
|
|
} else if (num_imports == 0) {
|
|
|
|
obj.write(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s << g_olean_end_file;
|
|
|
|
}
|
|
|
|
|
2013-12-29 03:20:04 +00:00
|
|
|
bool environment_cell::load_core(std::string const & fname, io_state const & ios, optional<std::string> const & mod_name) {
|
|
|
|
if (!mod_name || mark_imported_core(fname)) {
|
2013-12-31 02:20:36 +00:00
|
|
|
std::ifstream in(fname, std::ifstream::binary);
|
2013-12-29 03:20:04 +00:00
|
|
|
if (!in.good())
|
|
|
|
throw exception(sstream() << "failed to open file '" << fname << "'");
|
2013-12-29 01:31:35 +00:00
|
|
|
deserializer d(in);
|
|
|
|
std::string header;
|
|
|
|
d >> header;
|
|
|
|
if (header != g_olean_header)
|
2013-12-29 03:20:04 +00:00
|
|
|
throw exception(sstream() << "file '" << fname << "' does not seem to be a valid object Lean file");
|
2013-12-29 01:31:35 +00:00
|
|
|
unsigned major, minor;
|
|
|
|
// Perhaps we should enforce the right version number
|
|
|
|
d >> major >> minor;
|
|
|
|
try {
|
2013-12-29 03:20:04 +00:00
|
|
|
if (mod_name)
|
|
|
|
add_neutral_object(new import_command(*mod_name));
|
2013-12-29 01:31:35 +00:00
|
|
|
while (true) {
|
|
|
|
std::string k;
|
|
|
|
d >> k;
|
|
|
|
if (k == g_olean_end_file) {
|
2013-12-29 03:20:04 +00:00
|
|
|
if (mod_name)
|
|
|
|
add_neutral_object(new end_import_mark());
|
2013-12-29 01:31:35 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
read_object(env(), ios, k, d);
|
|
|
|
}
|
|
|
|
} catch (...) {
|
2013-12-29 03:20:04 +00:00
|
|
|
if (mod_name)
|
|
|
|
add_neutral_object(new end_import_mark());
|
2013-12-29 01:31:35 +00:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2013-08-08 23:12:46 +00:00
|
|
|
}
|
|
|
|
|
2013-12-29 03:20:04 +00:00
|
|
|
bool environment_cell::import(std::string const & fname, io_state const & ios) {
|
2013-12-29 11:43:45 +00:00
|
|
|
flet<bool> set(m_type_check, !m_trust_imported);
|
2013-12-29 03:20:04 +00:00
|
|
|
return load_core(realpath(find_file(fname, {".olean"}).c_str()), ios, optional<std::string>(fname));
|
|
|
|
}
|
|
|
|
|
|
|
|
void environment_cell::load(std::string const & fname, io_state const & ios) {
|
|
|
|
load_core(fname, ios, optional<std::string>());
|
|
|
|
}
|
|
|
|
|
2014-01-15 00:41:40 +00:00
|
|
|
bool environment_cell::imported(std::string const & n) const {
|
|
|
|
return already_imported(name(realpath(find_file(n, {".olean"}).c_str())));
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_cell::environment_cell():
|
|
|
|
m_num_children(0) {
|
2013-12-29 11:43:45 +00:00
|
|
|
m_trust_imported = false;
|
|
|
|
m_type_check = true;
|
2013-12-13 00:33:31 +00:00
|
|
|
init_uvars();
|
2013-08-08 23:12:46 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_cell::environment_cell(std::shared_ptr<environment_cell> const & parent):
|
|
|
|
m_num_children(0),
|
|
|
|
m_parent(parent) {
|
2013-12-29 11:43:45 +00:00
|
|
|
m_trust_imported = false;
|
|
|
|
m_type_check = true;
|
2013-12-13 00:33:31 +00:00
|
|
|
parent->inc_children();
|
2013-09-01 23:59:15 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_cell::~environment_cell() {
|
|
|
|
if (m_parent)
|
|
|
|
m_parent->dec_children();
|
2013-09-01 23:59:15 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment::environment():
|
2013-12-24 19:32:09 +00:00
|
|
|
m_ptr(std::make_shared<environment_cell>()) {
|
2013-12-13 00:33:31 +00:00
|
|
|
m_ptr->m_this = m_ptr;
|
|
|
|
m_ptr->m_type_checker.reset(new type_checker(*this));
|
2013-08-06 03:06:07 +00:00
|
|
|
}
|
2013-08-24 23:11:35 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
// used when creating a new child environment
|
|
|
|
environment::environment(std::shared_ptr<environment_cell> const & parent, bool):
|
2013-12-24 19:32:09 +00:00
|
|
|
m_ptr(std::make_shared<environment_cell>(parent)) {
|
2013-12-13 00:33:31 +00:00
|
|
|
m_ptr->m_this = m_ptr;
|
|
|
|
m_ptr->m_type_checker.reset(new type_checker(*this));
|
2013-11-18 02:11:44 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
// used when creating a reference to the parent environment
|
|
|
|
environment::environment(std::shared_ptr<environment_cell> const & ptr):
|
|
|
|
m_ptr(ptr) {
|
2013-11-18 02:11:44 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
ro_environment::ro_environment(environment const & env):
|
|
|
|
m_ptr(env.m_ptr) {
|
2013-11-07 19:29:01 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
ro_environment::ro_environment(weak_ref const & r) {
|
|
|
|
if (r.expired())
|
|
|
|
throw exception("weak reference to environment object has expired (i.e., the environment has been deleted)");
|
|
|
|
m_ptr = r.lock();
|
2013-11-07 03:21:22 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension::environment_extension():
|
2013-11-07 03:21:22 +00:00
|
|
|
m_env(nullptr),
|
|
|
|
m_extid(0) {
|
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension::~environment_extension() {
|
2013-11-07 03:21:22 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension const * environment_extension::get_parent_core() const {
|
2013-11-07 03:21:22 +00:00
|
|
|
if (m_env == nullptr)
|
|
|
|
return nullptr;
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_cell * parent = m_env->m_parent.get();
|
2013-11-07 03:21:22 +00:00
|
|
|
while (parent) {
|
|
|
|
if (m_extid < parent->m_extensions.size()) {
|
2013-12-13 00:33:31 +00:00
|
|
|
environment_extension * ext = parent->m_extensions[m_extid].get();
|
2013-11-07 03:21:22 +00:00
|
|
|
if (ext)
|
|
|
|
return ext;
|
|
|
|
}
|
|
|
|
parent = parent->m_parent.get();
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-11-12 04:29:53 +00:00
|
|
|
|
2013-12-13 00:33:31 +00:00
|
|
|
read_only_shared_environment::read_only_shared_environment(ro_environment const & env):
|
2013-11-12 04:29:53 +00:00
|
|
|
m_env(env),
|
2013-12-13 00:33:31 +00:00
|
|
|
m_lock(const_cast<environment_cell*>(m_env.m_ptr.get())->m_mutex) {
|
2013-11-12 04:29:53 +00:00
|
|
|
}
|
2013-12-12 19:19:09 +00:00
|
|
|
read_only_shared_environment::~read_only_shared_environment() {}
|
2013-11-12 04:29:53 +00:00
|
|
|
|
2013-12-12 19:19:09 +00:00
|
|
|
read_write_shared_environment::read_write_shared_environment(environment const & env):
|
2013-11-12 04:29:53 +00:00
|
|
|
m_env(env),
|
|
|
|
m_lock(m_env.m_ptr->m_mutex) {
|
|
|
|
}
|
2013-12-12 19:19:09 +00:00
|
|
|
read_write_shared_environment::~read_write_shared_environment() {}
|
2013-12-30 05:59:57 +00:00
|
|
|
|
|
|
|
static std::unique_ptr<name_map<std::pair<mk_builtin_fn, bool>>> g_available_builtins;
|
|
|
|
name_map<std::pair<mk_builtin_fn, bool>> & get_available_builtins() {
|
|
|
|
if (!g_available_builtins)
|
|
|
|
g_available_builtins.reset(new name_map<std::pair<mk_builtin_fn, bool>>());
|
|
|
|
return *g_available_builtins;
|
|
|
|
}
|
|
|
|
|
2013-12-30 20:19:00 +00:00
|
|
|
void register_builtin(name const & n, mk_builtin_fn mk, bool is_builtin_set) {
|
2013-12-30 05:59:57 +00:00
|
|
|
auto & bs = get_available_builtins();
|
|
|
|
if (bs.find(n) != bs.end())
|
2014-01-07 22:34:21 +00:00
|
|
|
throw exception("invalid builtin object, system already has a builtin object with the given name"); // LCOV_EXCL_LINE
|
2013-12-30 05:59:57 +00:00
|
|
|
bs[n] = mk_pair(mk, is_builtin_set);
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<std::pair<expr, bool>> get_builtin(name const & n) {
|
|
|
|
auto it = get_available_builtins().find(n);
|
|
|
|
if (it != get_available_builtins().end())
|
|
|
|
return optional<std::pair<expr, bool>>(it->second.first(), it->second.second);
|
|
|
|
else
|
|
|
|
return optional<std::pair<expr, bool>>();
|
|
|
|
}
|
2013-07-29 05:34:39 +00:00
|
|
|
}
|